Car Heater (winter is coming) need coding help!

Hej,

Här är hela “paketet”

https://paste.ubuntu.com/p/HB4pv8ctNC/

Tackar så mycket.

Vad säger ni, ska vi göra ett gemensamt försök att skriva om detta till ett blueprint?

Jag tänker att logiken ska vara att man sätter värme-faktor som en slider och sen räknar man ut hur många minuter som behövs baserat på temp.

variables:
  outside_temperature: -10  # °C
  comfort_temperature: 20  # °C
  delta_temperature: {{ outside_temperature - comfort_temperature }}  # -30
  heat_factor: 4
  running_time: {{ delta_temperature * heat_factor }}  # will be -30 * 4 = -120 minutes (2h)
  departure_time: '07:30'
  start_time: >-
    {{ ('1970-01-01T' departure_time |  as_timestamp() - (running_time * 60)|abs ) | timestamp_custom("%H:%M:%S")}}  # 05:30:00

Jag är dock osäker på om man kan använda variabler som trigger-tid i sin automation, typ:

trigger:
  platform: time
  at: start_time

action:
- service: switch.turn_on
  entity_id: !input car_heater
- domain: mobile_app
  type: notify
  device_id: !input notify_device
  message: >-
   The car heater is turned on to have the car warm 
   ({{comfort_temperature}}) at {{ depatrure_time }}.

Edit:

Tror inte jag räknar rätt här: https://www.omnicalculator.com/physics/specific-heat?advanced=1&c=SEK&v=equation:0,T:30!C,T1:-10!C,c:1003.5!jkgk,substance:2896405214,m:5.1!kg
men det antyder att det skulle behövas 42Wh att värma 4 m3 luft (jag har plockat värdena från https://www.wolframalpha.com/input/?i=4+cubic+meter+air), alltså en gammal glödlampa på 40W i en timme. Men, mitt antagande om att använda en konstant tror jag funkar bra då det ser ut att vara en linjär funktion (energi per °K man vill värma).

Känner mig som Lucky Lule (snabbare än min egna skugga).

yaml
blueprint:
  name: Car heater
  description: Activate car heater based on sensor temperature
  domain: automation
  input:
    temp_sensor:
      name: Reference temperature sensor
      selector:
        entity:
          domain: sensor
          device_class: temperature
    car_heater_switch:
      name: Car heater switch
      selector:
        entity:
          domain: switch
    time_to_leave:
      name: Time to leave
      description: The time the car should be warm
      default: '7:00:00'
      selector:
        time: {}
    factor:
      name: Heat factor
      description: >
        The heating factor indicates how fast the car will get heated
         a value of 4.0 means that it takes 4 minutes to heat 1°C.
      default: 4.0
      selector:
        number:
          min: 0.1
          max: 10.0
          step: 0.1
          mode: slider
    comfy_temp:
      name: Comfort temperature
      description: Target temperature
      default: 18
      selector:
        number:
          min: 5
          max: 25
          step: 1
          unit_of_measurement: °C
          mode: slider
    notify_device:
      name: Device to notify
      description: Device needs to run the official Home Assistant app to receive notifications.
      selector:
        device:
          integration: mobile_app

variables:
  temp_sensor: !input temp_sensor
  comfort_temperature: !input comfy_temp
  heat_factor: !input factor
  departure_time: !input time_to_leave

trigger:
  - platform: time_pattern
    minutes: '*'
condition:
  - condition: template
    value_template: >-
      {% set running_time_sec = ((float(states(temp_sensor)) -
      float(comfort_temperature)) * float(heat_factor) * 60) | abs %} {% set
      depature_time_today = as_timestamp(as_timestamp(utcnow()) |
      timestamp_custom('%Y-%m-%d ') ~ departure_time) %}                                                                                                                             
      {{ depature_time_today - as_timestamp(utcnow()) }} {{ running_time_sec }} 
      {{ (depature_time_today - as_timestamp(utcnow())) < running_time_sec  and
      depature_time_today > as_timestamp(utcnow())}}
action:
  - service: switch.turn_on
    entity_id: !input car_heater_switch
  - domain: mobile_app
    type: notify
    device_id: !input notify_device
    message: >-
      The car heater is turned on to have the car warm
      ({{comfort_temperature}}°C) at ''{{ departure_time }}''.
      {{((states(temp_sensor)|float - float(comfort_temperature)) 
      * heat_factor) | abs + 2 }}
    title: 'Car heater {{ states(temp_sensor)}}°C @ {{utcnow()}}'
  - wait_template: false
    continue_on_timeout: true
    timeout: 
      minutes: >-
        {{ ((states(temp_sensor)|float - float(comfort_temperature)) 
        * heat_factor) | abs + 2}}
  - service: switch.turn_off
    entity_id: !input car_heater_switch
  - domain: mobile_app
    type: notify
    device_id: !input notify_device
    message: >-
      The car heater is turned OFF to have the car warm
      ({{comfort_temperature}}°C) at {{departure_time}}.
      {{((states(temp_sensor)|float - float(comfort_temperature)) 
      * heat_factor) | abs + 2 }}
    title: 'OFF Car heater {{ states(temp_sensor)}}°C @ {{utcnow()}}'

mode: single

Grymt med en blueprint! funkar klockrent.
Varför har du inte lagt upp den i blueprint Exchange?
Har inte riktigt kunskapsnivån att bidra så mycket själv tyvärr men funderar på om det på nåt fiffigt sätt går att integrera med Lovelace för att kunna ändra avresetid? likt orginal posten?

1 Like

Alyhough I welcome a Swedish take on this (as we Nordics seem to be the only ones to care), I do belive that we should keep to English as long as there are no national subforums.

With combined efforts there might be the possiblity to come up with a sensible blueprint.

For me the requirements are:

  • scalable to more than one vehicle
  • scheduling should not be limited to one departure per day (ie morinng to office (will we ever return to that kind of regularity?), but should cater for departures at other regulrar intervals for afternoon/evening activities (kids to various sports, your better half attending various activities etc), ie a weekly schedule
  • ad hoc departure with pre-annmouncement, ie at 13hrs we will go to visit grandpa/supermarket/whatever

What I have done is that I have compiled a solution from bits and pieces in the forum, but ended up with with a template sensor being the heart of the logics rather than an automation.
Currently I am happy with my ad hoc departure solution, ie I can set departure in advance and the heater will turn on in accordance to a linear algorithim as recommended by “Gröna bilister”:
-15C => 90 minutes
0C => 60 minutes
10C => 0 minutes
http://www.gronabilister.se/fakta-bil-miljo/du-avgor-bilens-bransleforbrukning/motorvarmare
The linerar equtions in thus:

{% set mv_tid = ((-0.5 * tempdeg) + 30) | int %}

My initial attempt in terms of automation can be found here:

1 Like

Good point about the english.
I looked in to your automation and it sure looks nice! But a blueprint creating the same would be awesome, especially for a beginner like myself.
Maybe some inspiration insetting the departure time could be picket from here? Wake-up light alarm with sunrise effect

I agree on the requirements!

Okay, so Ive started to put som code together, tanks to @marieper and the Wake-up light alarm with sunrise effect
Home assistant does not accept the code with the tamplate action but i think i got the input selections right.
When i try to import the blueprint i get this fault message "

Failed to load blueprint: while scanning for the next token found character ‘%’ that cannot start any token in “/config/blueprints/automation/Egna/car_heater_v01.yaml”, line 42, column 6

Maybe someone who actually know how write templates could help out with that bit?
I tried to replace the departure time with a input_datetime helper and changed the formula

blueprint:
  name: Carheater based on outside temperature
  description: 'Note: Requires time sensor in configuration and input boleean for manual activation'
  domain: automation
  input:
    switch_entity:
      name: Car heater outlet
      description: The outlet to control.
      selector:
        entity:
          domain: switch
    timestamp_sensor:
      name: Alarm timestamp sensor
      description: 'Sensor with timestamp of departure time'
      default: none
      selector:
        entity:
          domain: input_datetime
    outside_temperature:
      name: Outside temperature sensor
      description: 'Outside temperature sensor'
      selector:
        entity:
          device_class: temperature
variables:
  switch_entity: !input 'switch_entity'
  timestamp_sensor: !input 'timestamp_sensor'
  outside_temperature: !input 'outside_temperature'
trigger:
- platform: time_pattern
  minutes: '*'
condition:
   - condition: template
     value_template: '{{ states(''outside_temperature'') | float <= 10
       }}'
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 time
    {% set dept_time = states('timestamp_sensor') | 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_time))) %}
  # 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('outside_temperature') | float %}
  # this gets the minute offset from the start based on the temperature #}
    {% set offset_mins = ((-0,5 * tempdeg) + 30) | 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_entity
  initial_state: true
mode: single
max_exceeded: silent

I believe that

should read

action:
  - service_template: >-

I have also given some thought to the pros and cos with having a linear fomula for the run time estimation versus a dumb case construction. The formula is more elegant and allows for it to be turned into a template sensor, but the run time might not fit the users climate conditions.
Using a case condition makes it easier to set your own duration for 10oC; 5; 0; -5; -10; -15; -20 (or whatever intervalls the final blueprint ends up with).

Some time ago I opened a general discussion on the usage of system templates versus automations executed every minute just to check conditions, using the orignal post for the service template used here as an example, where @Mutt expressed that much of that discussion centered around the aim to have a very minimalistic approach - so it might not be the optimal approach from our perspective…

So in the end it might be better to have four input_number helpers
runtime_ten_deg
runtime_zero_def
runtime_mten_deg
runtime_mtwenty_deg
which the blueprint user has to define up front, and can set to his/her liking.

Due to the cold weather for the last week, I have adjusted my formula to:
(-6 * tempdeg) + 60)
which give 1h runtime at +10 and 3h at -20.

The difference being the space removal character ‘-’ ???
I’ve never seen an instance where this makes a difference.
Test it in the template editor and tell me how it improves things.
I like the idea of being able to specify the mx + c line but to be frank I don’t think that many people will be bothered or able to implement it, good luck with that though, I hope to be proved wrong

Well, one learns a new thing everyday :slight_smile:

Python/YAML is not my backyard, far from it, I’m more of a bash guy… and I have to admit that all these small sort of compilator/parser directives/tokens (ie space removal in this particular case) drives me mad once in a while… In my own little world the “-” was part of the redirect(?) “>”, as the rest of the template seemed copy-pasted from the other discussion, where we know it works in that automation.

So obviusly i`m quite new to this but it´s very fun to learn how templates and jinja works.
So at the moment im stuck trying to figure out the “datetime” function. https://www.home-assistant.io/docs/configuration/templating/
what i want is to use the “timestamp” from a input.datetime sensor

{% set settime = (state_attr('input_datetime.motorvarmare2', 'timestamp')) %}

Insted of two input sensors as in the original code.
That timestamp is in seconds from midnight
And then to use the maths in the rest of the code, but to get it to work i need to get the

timestamp now()

as only seconds from midnight, not the entire date. I have tried varius filters and settings but cant seem to get it to work.
Here is my code so far:
(the prints are just for debugging)

{% set settime = (state_attr(‘input_datetime.motorvarmare2’, ‘timestamp’)) %}
{% print settime %}
{% set timenow = (as_timestamp(now())) | timestamp_local %}
{% print timenow %}
{% set time = strptime(timenow,‘%H::%M’)%}
{% print time %}
{% set test = (as_timestamp(timenow))%}
{% print test %}

this outputs:

36540
2021-02-08 13:06:00
2021-02-08 13:06:00
1612785960.0

Found the solution here: SOLVED: Time trigger with input_datetime not working - #15 by ftastisch

Now its looks like this:

{# 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 = now().hour * 3600 + now().minute * 60 + now().second %} {# this sets your 'settime' as a huge number and stores in settime #} {% set settime = (state_attr('input_datetime.motorvarmare2', 'timestamp')) %} {# 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.termometer_ute_ch4_temperature') | float %} {# this gets the minute offset from the start based on the temperature #} {% set offset_mins = ((-2 * tempdeg) + 60) | 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 {% endif %}

Now i just need to put it all together and clean it up a bit, but that’s for another day.

1 Like

Okay so i got a functioning automation:

id: '1613303438594'
  alias: carheater_master
  description: ''
  trigger:
  - platform: template
    value_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 number in seconds from midnight. #}
      {% set timenow = now().hour * 3600 + now().minute * 60 + now().second %}
      {# this sets your 'settime' as a number from your input sensor and stores in settime #}
      {% set settime = (state_attr('input_datetime.motorvarmare2','timestamp')) %}
      {# this gets the temperature (as a float, as that will aid in resolution) #}
      {% set tempdeg = states('sensor.termometer_ute_ch4_temperature')| float %}
      {# this gets the minute offset from the start based on the temperature#}
      {% set offset_mins = ((-2 * tempdeg) + 60) | int %}
      {# given the 'offset' we now have a new 'start time' calculated, based on temperature #}
      {% set heatstart = settime - (offset_mins * 60) %}
      {# this will render true when its time to start the heter and trigger the automation #}
      {% if timenow >= heatstart %} true {% else  %} false {% endif%}"
  - platform: state
    entity_id: input_boolean.motorvarmare2
    to: 'on'
  condition: []
  action:
  - service: switch.turn_on
    data: {}
    entity_id: switch.shellyswitch25_84cca8b07a6d_channel_2
  - delay: 02:00:00
  - service: switch.turn_off
    data: {}
    entity_id: switch.shellyswitch25_84cca8b07a6d_channel_2
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.motorvarmare2
  mode: single

But now i can’t get the blueprint to work properly.

the blueprint now looks like this:

blueprint:
  name: Carheater based on outside temperature
  description: 'Will start the car heater based on the formula y= -2*x+60 meaning 0deg C= 60min, -15deg C=90min Note: Requires two helpers Time(input_datetime) sensor with time only and toggle(input_boolean) for manual activation. Configuration->Helpers->add helper'
  domain: automation
  input:
    switch_entity:
      name: Car heater outlet
      description: The outlet to control.
      selector:
        entity:
          domain: switch
    timestamp_sensor:
      name: Alarm timestamp sensor
      description: 'Sensor with timestamp of departure time'
      selector:
        entity:
          domain: input_datetime
    manual_boolean:
      name: Manual activation
      description: 'Input boolean used for manual activation'
      selector:
        entity:
          domain: input_boolean
    outside_temperature:
      name: Outside temperature sensor
      description: 'Outside temperature sensor'
      selector:
        entity:
          device_class: temperature
    delay_time:
      name: The maximum time for the heater to run
      description: 'The maximum time for the heater to run, default 2h'
      default: 02:00:00
      selector:
        time:
variables:
  sensor: !input timestamp_sensor
  outside_temperature: !input outside_temperature
trigger:
  - platform: template
    value_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 number in seconds from midnight. #}
      {% set timenow = now().hour * 3600 + now().minute * 60 + now().second %}
      {# this sets your 'settime' as a number from your input sensor and stores in settime #}
      {% set settime = (state_attr('sensor','timestamp')) %}
      {# this gets the temperature (as a float, as that will aid in resolution) #}
      {% set tempdeg = states('outside_temperature')| float %}
      {# this gets the minute offset from the start based on the temperature#}
      {% set offset_mins = ((-2 * tempdeg) + 60) | int %}
      {# given the 'offset' we now have a new 'start time' calculated, based on temperature #}
      {% set heatstart = settime - (offset_mins * 60) %}
      {# this will render true when its time to start the heter and trigger the automation #}
      {% if timenow >= heatstart %} true {% else  %} false {% endif%}"
  - platform: state
    entity_id: !input manual_boolean
    to: 'on'
action:
  - service: switch.turn_on
    entity_id: !input switch_entity
  - delay: !input delay_time
  - service: switch.turn_off
    entity_id: !input switch_entity
  - service: input_boolean.turn_off
    entity_id: !input manual_boolean
mode: single 

but apparently having variables in triggers is not supported…

2 Likes

This is exactly what I tried to do in my blueprint but also taking into account that different car heaters heat differently fast. (heat_factor)

That is what I already did in my code. What are you trying to do that I didn’t do?

Yes, the departure time should of course be an external sensor but as notifications for this thread somehow was turned off I figured that no one was interested in this (I’ve not seen this discussion).

I’ll update my blueprint…

I think you need to create one automation per vehicle. When it comes to scheduling I think ti is best to connect our automation to a calendar and add all events there (Google Calendar - Home Assistant).

What do you think?
@vilhelm.carlsson @marieper

Also, I don’t quite follow why you left my linear calculation going back to the less dynamic lookup method.

I’ve used comfort_temperature and heat_factor as “target temperature” and slope variable, as my use it to use this for my “cupèvärmare” (which on my Volvo heats so fast that a heat_factor of 0,5 works really well to have the care warm and cozy at departure time).

@fredrike - I don’t think anyone “left” your solution, as it was more you leaving the discussion, although involentary…

@vilhelm.carlsson has made an attempt to a published blueprint, to his best effort. I can not condem him for his choice of inspriation to the actual logic, as he only had your code snipets, which can be usefull for the compiled solution, but being just snipets makes them a little more difficult to integrate unless thinking along the same path.
If you have a working blueprint, please show it, as discussed above the idea is to have a collaborative solution, and in that regards everyone’s effort counts - and at the same time some ideas will be rejected.

Currently I have a solution that “works” for me but it is entirely based on template sensors and thus not easily transferred to a blueprint. As you too indicate, it reiles on google calender for any of the regular departures (which I am not too happy with as I want to keep the solution within my four walls, but it was the quickest solution). All in all it seemed like a elegant solution which removed the need of having time pattern based automation fireing every umpteen minutes to evaulate the trigger condition (outside temp rise/drop). The downsides are:

  • the template sensor is evalutated all year round, while an automation can be turned off summer time
  • it depends on external source in terms of Google calendar, this can be mitigated by installing a private iCal solution

so I’m not that satisfied with my solution, but neither have I contributed that much to the public solution, so I feel that I have no right to complain.

1 Like

(Car Heater (winter is coming) need coding help! - #38 by vilhelm.carlsson):

@vilhelm.carlsson Fick du till något trevligt lovelacekort?

Yes i did!

I set the depature time or if i want to instantly start i switch the ”motorvärmare” on, could convert it to the new button feature perhaps.
I have the entity(shelly) visible just for manual feedback.
Been using the automation successfully so far.

1 Like

To be honest i don’t follow how (-0,5x)+30 follows The gröna bilister recommendation.

(-0,5*-15)+30 =37,5
(-0,50)+30= 30
(0,5
10)+30= 25

While my equation (-2x)+60
(-2*-15)+60= 90
(-20)+60 = 60
(-2
10)+ 60 = 40, typically i just use the heater if the forecast i below 0 degrees.