basic arithmetic in Home Assistant to calculate how much heating oil I need and when I need to order heating oil
My boiler burns heating oil from a tank and unlike the ‘gas’ that most homes burn it’s finite – so when it’s gone I’m cold. Ordering heating oil is tricky because I must say exactly how much I need and estimate when I need it. Two things massively help here: a tank oil level sensor shows how much oil I must order. (I made two ESPhome sensors: here and here). I get Home Assistant to email me the current oil level and store it in a Google spreadsheet (see how this is done here).
A Google spreadsheet was a big help before all this was done in Home Assistant. The spreadsheet stored daily oil levels and calculated when oil was needed based on average daily oil use (which varies somewhat). Furthermore, I must allow for 10 – 14 days for the order to arrive. For example, I might need to order 120 litres more than today’s oil level (10 days * 12 litres /day).
doing calculations in Home Assistant comes with these challenges that we’ll tackle …
Home Assistant features / concepts / skills:
- storing variables – e.g. store yesterday’s oil level so that I can work out how much oil I’ve used since then
- storing constants – as above e.g. the capacity of the oil tank and how many days the order takes to arrive are fairly constant
- email notifications – e.g. sending myself an email with today’s oil status
- recording in a spreadsheet – e.g. keeping a log of oil levels and daily temperatures for interest
- calculating averages over time – e.g. the average daily oil use over several days
- doing a calculation at midnight each day in a Home Assistant Automation
- doing a calculation within a Home Assistant template helper
storing variables and constants in Home Assistant
For example: I need to keep yesterday’s oil level (to work out the amount of oil I’ve used since then). Home Assistant recommend using an input number to store variables and constants. Go to Settings > Devices & Services > Helpers > Create helper > Number
Make these input numbers to use in the calculations:
oilorderdelay = when I order more oil I can chose how urgently I want the oil. Initial value is 10 (days) = cheaper.
oiltanklimit = the size of my oil tank or the lowest level the oil may drop to before ordering more oil. Initial value is 800 (litres). My oil level sensor tells me how much oil I need to order today. The tank capacity is used to calculate when the oil will get used up.
If you don’t use the ‘frontend UI’ to make an input number (as above) you can instead edit your configuration.yaml to create an input number. Here you’re able to set the step size, add units and whether to use a ‘slider’ or ‘box’ to adjust its value if needed.
# CREATE VARIABLES TO STORE YESTERDAYS OIL LEVEL - USE File Editor TO ADD THIS TEXT TO configuration.yaml input_number: midnight_oil_level: name: midnight oil level min: -1000 max: 1000 step: 1 unit_of_measurement: L icon: mdi:oil-level mode: slider # alternative to 'slider' is 'box' oil_level_yesterday: name: oil level yesterday min: -1000 max: 1000 step: 1 unit_of_measurement: L icon: mdi:oil-level mode: slider oil_used_yesterday: name: oil used yesterday min: -1 max: 1000 step: 1 unit_of_measurement: L icon: mdi:oil-level mode: slider
calculate the average amount of oil used over five days
Home Assistant allows us to create a new sensor such as the ‘average daily oil use’ calculated from the last five days of oil use. Edit the Home Assistant file configuration.yaml and add this code to the sensor: section. This new statistics sensor watches the value of the input number we set up earlier.
sensor: # USE File Editor TO ADD THIS TEXT TO THE SENSOR SECTION OF configuration.yaml - platform: statistics name: "average daily oil use" entity_id: input_number.oil_used_yesterday state_characteristic: mean max_age: days: 5 precision: 0
a Home Assistant Automation to do a calculation at midnight each day
At midnight each day I save the oil level and subtract it from the oil level I saved yesterday.
Doing a calculation in Home Assistant involves unreasonably clumsy code. Everytime you want to refer to the oil level you must use a states () statement and enclose the entire calculation inside moustache brackets. For example, this statement calculates the amount of oil_used_yesterday.
{{ states(‘input_number.midnight_oil_level’) | int – states(‘sensor.oil_level’) | int }}
# IT'S NOW POSSIBLE TO USE THE FOLLOWING IN AN AUTOMATION IN THE IU. ALTERNATIVELY YOU CAN # SAVE THE FOLLOWING AS A FILE CALLED oil.yaml INSIDE THE HOME ASSISTANT 'automations' FOLDER #id: '696998989' # YOU NEED A RANDOM ID NUMBER IF YOU CREATE AN AUTOMATION AS A FILE. alias: OIL - oil recorder description: save oil level at midnight as a 'input number' trigger: - platform: time at: "23:55:05" action: - service: input_number.set_value data_template: entity_id: input_number.oil_used_yesterday value: >- {{ states('input_number.midnight_oil_level') | int - states('sensor.oil_level') | int }} - service: input_number.set_value data_template: entity_id: input_number.oil_level_yesterday value: "{{ states('input_number.midnight_oil_level') | int }} " # THE CODE BELOW SENDS ME AN EMAIL AS WELL AS POST TO A GOOGLE SPREADSHEET eg via IFTTT - data: event: oil_level value1: "{{ states('sensor.oil_level')}}" value2: "{{ states('sensor.temperature_weath')}}" value3: "{{ states('input_number.oil_used_yesterday')}}" service: ifttt.trigger - service: input_number.set_value data_template: entity_id: input_number.midnight_oil_level value: "{{ states('sensor.oil_level') | int }} " # THE CODE BELOW SENDS ME AN EMAIL - service: notify.mail_roger data: message: >- oil report at {{ states ('sensor.time') }} from boiler room. Order oil in {{ states ('sensor.how_many_days_till_i_order') }} days on date {{ (as_timestamp(now()) + (states('sensor.how_many_days_till_i_order')|float*24*3600)) | timestamp_custom("%d /%m", True) }}. Presently you can order {{ states ('sensor.how_much_oil_do_i_order_today') }} litre title: oil {{ states ('sensor.oil_level') }} level mode: single
See the note in the code above and then see this page explaining how to save values to a Google spreadsheet
doing calculations using Home Assistant’s template feature
As well as do a calculation in an Automation you can also do calculations in Home Assistant inside a template helper. When I do a calculation in an Automation as above it’s done once a day. When you do calculations in Home Assistant inside a template helper the calculation is done continuously (which is unnecessary to be frank). Either way the code is clumsy. Go to Settings > Devices & Services > Helpers > Create helper > Template. Name the sensor ‘how much oil do I order today‘ and paste this code in the ‘state template’ box. (I’ll explain how the calculation works in the next section).
{{ - (states('sensor.oil_level')|int - states ('sensor.average_daily_oil_use')|int * states ('input_number.oilorderdelay')|int) }}
Make another Template Helper: name the sensor ‘how many days till I order’ and paste this code in the ‘state template’ box.
{{ ((states('sensor.oil_level')|int - ((states('input_number.oiltanklimit')|int + states ('sensor.average_daily_oil_use')|int * states ('input_number.oilorderdelay')|int )) ) / states ('sensor.average_daily_oil_use')|int) |int }}
notifications – send an email to yourself
It’s wise to set up Home Assistant with more that one notification method. This is partly because over time one of these methods will break and partly because an email notification at my desk suits notifying me about ordering oil. The email notifier requires the SMTP settings from your email service. Put the following section in your configuration.yaml
# PUT THIS IN configuration.yaml notify: - name: mail_roger platform: smtp server: smtp.my_provider.co.uk port: 587 timeout: 15 sender: !secret email@ encryption: starttls username: !secret email@ password: !secret email@password recipient: !secret email@ sender_name: home assistant notify # PUT THESE TWO LINES IN secrets.yaml email@: emailaddress-here email@password: password-here #the-protected_thing-goes_outside: the-secret-goes-inside
Lastly, put the following in an Automation that fires off once a day.
- service: notify.mail_roger
data:
message: >-
oil report at {{ states ('sensor.time') }} from boiler room. Order oil
in {{ states ('sensor.how_many_days_till_i_order') }} days on date {{
(as_timestamp(now()) +
(states('sensor.how_many_days_till_i_order')|float*24*3600)) |
timestamp_custom("%d /%m", True) }}. Presently you can order {{ states
('sensor.how_much_oil_do_i_order_today') }} litre
title: oil {{ states ('sensor.oil_level') }} level
the variables and the calculation explained
All of the above serves to calculate two things: ‘how many days till I order’ and ‘how much oil do I order today’.
I used Home Assistant input_numbers to store a number of variables including the oil level yesterday, the amount of oil I used yesterday, how much oil the tank can store and how many days until the oil company delivers the order. The first thing I calculate is how much oil I use while waiting for the order to arrive – I add this extra amount to the order. The amount affects the point where the oil level reminds me to order more oil.
I calculate ‘how many days till I order’ knowing the current oil level and divide this by the average daily use use. I add in the order delay in days.
I calculate ‘how much oil do I order today’. knowing the size of the oil tank, the current oil level and I add in the order delay.