Car engine heater for Nordic (and other cold climates)

For this solution

I combined the two existing soutions:

(curtesy @Mutt)
and

(curtesy @nylund)
I used the linear temperature fomula from second thread and the general automation of the first:

- id: '1601582133'
  alias: Motorvärmare Flagga Start (master)
  trigger:
  - platform: time_pattern
    minutes: /1
  condition:
  - condition: template
    value_template: '{{ states(''sensor.balkong_norr_temperature'') | float <= 10
      }}'
  - condition: or
    conditions:
      - condition: state
        entity_id: input_boolean.mv_flagga_automat_igang
        state: 'on'
      - condition: state
        entity_id: input_boolean.mv_flagga_manuell_tid
        state: 'on'
  action:
  - service_template: >
  {# This is a jinja comment and will be ignored by the interpreter #}
  {# ALL the below is indented more than it needs to be to show the comments more clearly #}
  {# This next line (all comments will be as this) gets the time RIGHT NOW and stores it as a
  {# HUGE number that has both date and time #}
    {% set timenow = as_timestamp(now()) %}
  {# this gets your input number hour (input_datetime is much easier) and stores as a number in hr #}
    {% set dept_hr = states('input_number.mv_flagga_timme') | int %}
  {# this gets your input number minute and stores as a number in mn #}
    {% set dept_mn = states('input_number.mv_flagga_minuter') | int %}
  {# this sets your 'settime' as a huge number and stores in settime #}
    {% set settime = as_timestamp(now().strftime("%Y-%m-%d " ~ '{0:0=2d}:{1:0=2d}'.format(dept_hr, dept_mn) ~ ':00')) %}
  {# as we've already done most of the work we just subtract 3 hours from the
  set time to start our evaluation #}
    {% set starttime = settime - (2*60*60) %}
  {# this tests to see if we are 'in' the 'slot' #}
    {% set slot = (starttime <= timenow < settime) %}
  {# this gets the temperature (as a float, as that will aid in resolution) #}
    {% set tempdeg = states('sensor.balkong_norr_temperature') | float %}
  {# this gets the minute offset from the start based on the temperature #}
    {% set offset_mins = ((-4 * tempdeg) + 40) | int %}
  {# given the 'offset' we now have a new 'start time' calculated, based on temperature #}
    {% set heatstart = settime - (offset_mins * 60) %}
  {# this tests that we are (now) in the 'slot' and 'that switch on time' is in the past #}
    {% set heat = slot and timenow >= heatstart %}
  {# this uses the last evaluation to determine if we switch 'on' or 'off' #}
    {% if heat %}
      switch.turn_on
  {# switch.turn_off is managed by separate automation that monitors the entity_id being ON for x:y hrs #}
    {% endif %}
     entity_id: switch.motorvarmare_flagga
  initial_state: true
  mode: queued
  max: 10

Then, rather then sending a switch_off emeddiately at the the departure time I have an action triggered automation that monitors the switch_on of the switch.motorvarmare_flagga, delays for 2h and then sends the off signal. This will ensure a warm car even if departure is delayed, and if I do leave on time, what is the problem with the power still being on?

- id: '1602700151078'
  alias: Motorvärmare Flagga Stopp (master)
  description: Slå av efter 2h
  trigger:
  - platform: state
    entity_id: switch.motorvarmare_flagga
    to: 'on'
    for: '2:10:00'
  condition: []
  action:
  - service: switch.turn_off
    data: {}
    entity_id: switch.motorvarmare_flagga
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.mv_flagga_manuell_tid
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.mv_flagga_automat_igang

The input_booleans are to differntiate between manual heating on, and heating provided by the schedule automations (this basically from stopping the main automation to pump order every minute).

The glance_card has the input_number values as a temporary workaround of HA not coping with narrow columns, most noticable in the native Android app where the number value is dropped from display.

The sceduling is then managed by separate automations that is time-triggered just 2h before planned departure, setting the input_values as well as the input_boolean.

And, yes, I did block the main atomation from flooding the loogbook by adding an exclude rule in configuration.yaml.

2 Likes

Really impressive car heater functionality and UI. Care to share on Github for those of us who aren’t that proficient writing yaml and lovelace yet? Would appreciate it a lot! Winter is coming brrr

1 Like

I can look into it.
The only complicated thing here is the lovelace interface, and this can in turn be simplified once the android bug related to input_number is resolved - as then corresponding entities can be removed from the glance card.
The two automatons should be possible to merely copy-paste into automations.yaml and editied for local entities for

  • temperature sensor
  • input number, hour
  • input number, minute
  • switch name
1 Like

Hello, thanks for sharing this automation. I have copied the two automatons and it seems to work fine for me. I think i got the glance card right as well with the same entities you have but do you mind explain what entites you have in your cards?

MV Mur aut… = “input_boolean.mv_flagga_automat_igang”?
Start… = “input_boolean.mv_flagga_manuell_tid”?
Starta nu = “switch.motorvarmare_flagga”?
Motorvärmare Mur 3 =“automation.motorvarmare_flagga_start_master”?

How do you display the time after “Motorvärmare Mur 3”? Is that the time which the automation runs between?

Hi,

For the glance card:

  • “MV Mur aut” - your assumption is correct: input_boolean.mv_flagga_automat_igang, it is the input.boolean helper to disable the car heater system all together
  • “Start” - again you are correct, it is a boolean to trigger the manual override, input_boolean.mv_flagga_manuell_tid
  • Starta nu" - third time lucky, it is the switch.motorvarmare_flagga to direclty turn on the switch out there

The automations listed at the bottom is a custom card:

type: custom:auto-entities
card:
  type: entities
  title: 'Automater:'
  show_header_toggle: false
filter:
  include:
    - entity_id: /motorvarmare_flagga_auto/
sort:
  method: name

and it relies on that the scheduled automations to start (and stop) are following a namining convention on the entity level, the custom card just displays the name of the automation so there is no magic in pulling the time from elsewhere

I have then added all regular departures to a Google calendar and use that to manage the atomations trigger template:

{% set time_now = as_timestamp(states('sensor.date_time_iso')) %}
{% set leave_time = as_timestamp(state_attr('calendar.mv_flagga_schema','start_time')) | int %}
{{ time_now >= ( leave_time - states('sensor.mv_tid')|int ) }}

coupled with a condition template:

{{ state_attr('calendar.mv_mur_schema','message') == 'MV Mur Vardag 07:45' }}

I hope it got a bit clearer for you.

1 Like

Full dashboard config:

      - type: vertical-stack
        cards:
          - type: glance
            entities:
              - entity: sensor.time
              - entity: sensor.balkong_norr_temperature
                name: Temp ute
              - entity: switch.motorvarmare_flagga
                name: MV Flagga
          - type: entities
            entities:
              - entity: input_boolean.mv_mur_automat_igang
              - type: custom:template-entity-row
                name: >-
                  Nästa schema -
                  {{state_attr('calendar.mv_mur_schema','message')}}
                state: >-
                  {{as_timestamp(state_attr('calendar.mv_mur_schema','start_time'))|timestamp_custom('%a
                  %H:%M')}}
                icon: mdi:calendar
          - type: custom:time-picker-card
            entity: input_datetime.mv_mur_avresetid
            hour_mode: 24
            hour_step: 1
            minute_step: 5
            second_step: 5
            name: 'Ställ in avresetid:'
            layout:
              embedded: false
              name: inside
              align_controls: center
            hide:
              name: false
            link_values: false
          - type: entities
            entities:
              - entity: input_boolean.mv_mur_manuell_tid
                name: registera avresetid --->
            state_color: false
            show_header_toggle: false
          - type: conditional
            conditions:
              - entity: input_boolean.mv_mur_manuell_tid
                state: 'on'
            card:
              type: entity
              entity: sensor.mv_mur_departure
              icon: mdi:clock
          - type: conditional
            conditions:
              - entity: switch.motorvarmare_mur
                state: 'off'
            card:
              type: button
              tap_action:
                action: toggle
              entity: switch.motorvarmare_mur
              icon_height: 50px
              name: Starta nu
          - type: conditional
            conditions:
              - entity: switch.motorvarmare_mur
                state: 'on'
            card:
              type: button
              tap_action:
                action: toggle
              entity: switch.motorvarmare_mur
              icon_height: 50px
              name: Motorvärmaren är igång!
          - type: custom:auto-entities
            show_empty: false
            card:
              type: entities
              title: 'Script:'
              show_header_toggle: false
            filter:
              include:
                - domain: script
                  entity_id: /mv_mur_/
                  state: 'on'
            sort:
              method: name
          - type: custom:auto-entities
            card:
              type: entities
              title: 'Automater:'
              show_header_toggle: false
            filter:
              include:
                - entity_id: /motorvarmare_mur_auto/
            sort:
              method: name```
2 Likes

It’s winter again and I can’t get this project to work. UI editor and automation errors.
I have Home Assistant Core 2022.9.7 and there have been changes to Hass.
Would be nice to have a “iron wire” how-to guide for this awesome project.

As there are so many ifs and buts depending on the individual setupI think it is hard to write the perfect guide, but let med try again, I might be repeating myself as of what has been discussed above, but here goes…
Note - this is working with HA 2022.11.1.

  1. In configuration.yaml add three sensors:
    • one for computing the needed runtime [sensor.mv_tid] using whatever outdoor temperature sensor available as input - the equation approximates 0 min @ 10oC → 60 min @ 0oC → 150 min @ -15oC
    • and another for computing the expected heating start time hh:mm for display in the dashboard [sensor.mv_flagga_departure], using a Date/Time helper as input (as well as the above template sensor)
    • and the third to have a local date time sensor [sensor.date_time_iso] (probably not needed, as now() should work equally good, but is now inbedded in too many templates for me to remove)
sensor:
  - platform: time_date
    display_options:
      - 'time'
      - 'date'
      - 'date_time_iso'

  - platform: template
    sensors:
      mv_tid:
        friendly_name: "Motorvärmare, sekunder"
        value_template: "{% set tempdeg = states('sensor.balkong_norr_temperature') | float %}
{% set mv_tid = ((-6 * tempdeg) + 60) | int %}
{% if tempdeg > 10.0 %} {% set mv_tid=0 %}{% else %} {% set mv_tid = (mv_tid * 60) | int %} {% endif %}
{{ mv_tid }}"

  - platform: template
    sensors:
      mv_flagga_departure:
        friendly_name: "Motorvärmare Flagga, starttid"
        value_template: "{{ (as_timestamp(states('input_datetime.mv_flagga_avresetid_ymd'),'Error')|int - states('sensor.mv_tid')|int) | timestamp_custom('%a %H:%M') }} "
  1. Create three helpers:

    1. input_datetime.mv_flagga_avresetid_ymd
      to register the requested departure time, as a Date and Time helper
    2. input_boolean.mv_flagga_automat_igang
      to handle/override any calandar based automations (summer, holidays etc), as a input_boolean helper
    3. input_boolean.mv_flagga_manuell_tid
      to manually “register” departure time, as a input_boolean helper
  2. Create automations to start and stop the heating, as I have two cars, and I wanted to learn/test blueprints, I created one blueprint for the manual start of the heater, and it acts via a script that takes paramters passed on from the blueprint to address which car/parking lot to act on.

    1. script to hande the manually set departure time:
alias: MV Flagga Manuell Tid
sequence:
  - wait_template: >-
      {% set current_date_time = as_timestamp(now()) %} {{ current_date_time  >=
      ( mv_manual_departure - states('sensor.mv_tid')|int ) }}
  - service: switch.turn_on
    data: {}
    entity_id: switch.motorvarmare_flagga
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.mv_flagga_manuell_tid
mode: parallel
max: 10
fields:
  mv_manual_departure:
    description: Requested departure time
  1. Blueprint to lauch the script above
blueprint:
  name: Motorvärmare XXX Manuell tid mha script (master)
  description: Motorvärmare, ad-hoc avresetid
  domain: automation

  input:
    avresetid_hhmm:
      name: Tidsvariabel avresetid som inmatad, hhmm
      selector:
        entity:
          domain: input_datetime
    avresetid_ymd:
      name: Tidsvariabel avresetid omräknad, ymd
      selector:
        entity:
          domain: input_datetime
    trigg_enty:
      name: Boolsk switch, vilken MV
      selector:
        entity:
          domain: input_boolean
    mv_script:
      name: MV script
      selector:
        entity:
         domain: script

variables:
  avresetid_hhmm: !input avresetid_hhmm
  avresetid_ymd: !input avresetid_ymd
  mv_script: !input mv_script
  trigg_enty: !input trigg_enty
  today_tomorrow: >-
    {% set current_date_time = as_timestamp(now()) %}
    {% set leave_time = states(avresetid_hhmm) %}
    {% set next_leave = as_timestamp(states.sensor.date.state + ' ' ~ leave_time) %}
    {% if current_date_time | int >= next_leave | int %}
      {{ next_leave | int + 86400 }}
    {% else %}
      {{ next_leave | int }}
    {% endif %}

trigger:
  platform: state
  entity_id: !input trigg_enty
  from: 'off'
  to: 'on'

condition: []

action:
  - service: input_datetime.set_datetime
    entity_id: !input avresetid_ymd
    data:
      timestamp: '{{ today_tomorrow }}'
  - service: script.turn_on
    data:
      variables:
        mv_manual_departure: '{{ today_tomorrow }}'
    entity_id: !input mv_script

mode: parallel
max: 10
  1. Automation to stop the heater
alias: Motorvärmare Flagga Stopp (master)
description: Slå av efter 2h
trigger:
  - platform: state
    entity_id: switch.motorvarmare_flagga
    to: 'on'
    for: '2:10:00'
  - platform: template
    value_template: >-
      {{ as_timestamp(now()) >=
      as_timestamp(state_attr('calendar.mv_mur_schema','start_time')) }}  
    alias: Avresetid
condition: []
action:
  - service: switch.turn_off
    data: {}
    entity_id: switch.motorvarmare_flagga
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.mv_flagga_manuell_tid
mode: single

On top of this I am also using the Google calendar integration to set up any regular departure times. In the future I would like to remove the dependency to a cloud based calender, but for now I have to live with it. For setting up and monitoring events in the calendar, see Google Calendar, please note that I still use the legacy syntax as the Calendar trigger was not around when I set this up, and also as I have a dynamic offset.

alias: Motorvärmare Flagga Auto Vardagar Morgon
description: ''
trigger:
  - platform: template
    value_template: >-
      {% set time_now = as_timestamp(states('sensor.date_time_iso'),'Error') %}

      {% set leave_time =
      as_timestamp(state_attr('calendar.mv_flagga_schema','start_time'),'Error') |
      int %}

      {{ time_now >= ( leave_time - states('sensor.mv_tid')|int ) }}
condition:
  - condition: template
    value_template: '{{ states(''sensor.balkong_norr_temperature'') | float <= 10 }}'
  - condition: state
    entity_id: input_boolean.mv_flagga_automat_igang
    state: 'on'
  - condition: state
    entity_id: binary_sensor.workday_sensor
    state: 'on'
  - condition: template
    value_template: >-
      {{ state_attr('calendar.mv_flagga_schema','message') == 'MV Flagga Vardag
      Morgon' }}
action:
  - type: turn_on
    entity_id: switch.motorvarmare_flagga
    domain: switch
mode: restart
initial_state: true
max: 10
3 Likes