measure heating oil use (or water tank level) with a A02YYUW ultrasonic sensor

This tank level sensor produces surprising detail about my heating oil usage. It’s a bit like a smart meter for oil so I now know say, how many litres I burned each day for the last month. An oil delivery is due in ten days time so I get Home Assistant to estimate how much oil to order based on my recent use.

other questions and posts on this topic:

measure oil or water tank liquid level with a sensor

how to make a heating oil tank level sensor that’s more useful than anything you can buy.

this sensor:

  • can measure oil level in any unit – litres, kWh, gallons or days until I need to refill the tank
  • displays the tank level on a time graph (uses Home Assistant history graph).
  • can send readings or alerts as an email or phone notification.
  • can calculate the date when you’ll need to order or tell you how much free space there is in the tank
  • show your oil usage on a Home Assistant energy dashboard
  • uses an A02YYUW ultrasonic sensor from DF robot (~£15 ebay)
  • uses any ESP32 development board with wifi (~ £6-£10). ESP8266 boards have been used by others.
  • could work outdoors and on battery power with a waterproof electrician’s housing. The battery power might be 6 x 18650 cells based on this power pack I made
  • the sensor could monitor the salt level in a water softener or the water level in a tank (ref Dr Zzz – youtube)

Background: many homes use diesel oil as a fuel to keep warm in winter. Over the course of a winter I might need 1500 litres of oil but I’ve no way to predict when I’ll need more oil or know how much to order. And I really don’t ever want to run out of oil. Although we call the liquid ‘heating oil’ you may call it diesel or white spirits or turps or paraffin or kerosine.

what’s needed for this project

  • A02YYUW ultrasonic sensor by DF Robot – you want the UART version and for ease of disconnection, the 4-pin / 4-wire connection (it is 50cm from sensor to ESP32). When set up in ESPHome you get a sensor that reads out distance in mm – however I’ll show below how this becomes litres or gallons. You don’t want the PWM and RS485 versions of the A02YYUW as they are ‘not supported by ESPHome’.
  • I use coloured Dupont wires, Dupont 4-pin shells or coloured 18 gauge stranded wires if the wires need to be long. I use heat shrink tubing over the connectors (2mm; 12mm).
  • you need soldering skills if you want to make reliable connections – however in a few years time you may have to replace a part, thus you’ll want to be able to swap out the sensor end or the ESP32 board.
  • if your tank is outdoors you’ll need waterproofing (eg Kafuter K-705 gel plus a box housing for the ESP32 and its 5v supply
  • an ESP32 development board: I use MH-ET LIVE ESP32 and D1 Mini32 types as we just need four pins (or five pins if you want to monitor temperature as well).
  • ESPHome and Home Assistant already set up on say, a Raspberry Pi
  • if you want notifications you need your email account server settings (optional)
  • if you want to keep long term records you’d need to send the data to Google Sheets (optional)

how to connect up an oil level sensor to a ESP32 development board

This is a replacement for my original oil tank level sensor using the ultrasonic JSN-SR04T that had been working reliably for years. However after five years the oil vapour destroyed the silicone and the sensor started falling apart and eventually failed. Silicone does protect the sensor from water damage so this would work on a water tank. A further limitation of the JSN-SR04T ultrasonic sensor is that it cannot measure at short range – it records the same level whether the tank is full or 20cm below full. When the level drops by 20cm (about 200 litres) the readings become very useful at alerting me to order more oil.

The A02YYUW ultrasonic sensor by DFrobot is able to measure from at close as 3cm to 450cm. It too is encased in silicone which may one day fail. A workaround might be to encase the sensor in a TPU-3D printed shell or use PU glue. (I understand that polyurethane is more resistant to oil whereas silicone is not. Did you know that you can remove silicone by soaking it in an alkane such as diesel?)

The sensor works by sending sound blips to the liquid surface and then measuring the ‘echo time’ to estimate how far away it is. The ESPhome software and the sensor sends a distance value and I can multiply that by a number to get readings in mm or litres or kW or even money. The calculation is simpler if your oil tank has a regular shape – so 10cm on my tank corresponds to 105 litres – but anything is doable with simple maths.

The A02YYUW ultrasonic sensor module has four pin connectors each terminating in a female Dupont ‘socket’. I used Dupont male to female wires because my ESP32 already had pins. As supplied the sensor red and black leads go to VCC (5v) and GND on an ESP32 module. The sensor GREEN goes to GPIO16 on the ESP32 and the sensor BLUE goes to GPIO17 on the ESP32. (You could instead use PINS GPIO32; GPIO33; GPIO34)

For my future reference I used these coloured Dupont wires:

  • ESP32 5v > my brown > red on A02YYUW sensor
  • ESP32 GND > my blue > black on A02YYUW sensor
  • ESP32 GPIO16 > my orange > green on A02YYUW sensor
  • ESP32 GPIO17 > my yellow > blue on A02YYUW sensor

The sensor needs to be fixed so that it points down at the surface of the oil in the tank (photo). I drilled a couple of 3mm holes in the tank lid/flap.

how to write the program and install it on the ESP32 development board

ESPHome is part of Home Assistant and lets you create code and the binary file for the ESP32/8266 chip.

My oil sensor is a ‘connected’ oil sensor. It takes readings, sends them to Home Assistant which will present them ‘live’ in various ways. To gain this connectivity you need a Home Assistant installation on a Raspberry Pi (shown in an earlier project). Go to the ESPHome section of Home Assistant and add a ‘new device’. Follow the process eg it’ll ask you for a name (eg oil) and you may be asked to fill in wifi details in a list of ‘secrets’.

Still in Esphome look for ‘Edit’ next to your new device. Add the following code making changes to suit your setup. Finally choose Install to upload this code to your ESP32 development board. (What you’ve done is to assemble a series of instructions and compiled them into a ‘bin file’ that you upload to a ESP32 dev board via a USB cable. The process of installing the file to the ESP is called flashing the firmware although what you’re doing might be called ‘installing the program’).


# THIS IS FOR AN ESP32 development board
#

esphome:
name: oil
friendly_name: oil
area: Cottage

esp32:
board: esp32dev
framework:
type: arduino

substitutions:
devicename: oil


# Enable logging
logger:

# Enable Home Assistant API
api:
encryption:
key: "FtKhT5Sf4cwe5bh/N0Kzy6JMM5LG79H38rfceMlBHrE"

ota:
- platform: esphome
password: ""
# password: !secret ha_password

wifi:
networks:
- ssid: !secret wifiD_ssid
password: !secret wifiD_password
- ssid: !secret ee_ssid
password: !secret ee_password
- ssid: !secret wifi_ssid
password: !secret wifi_password

# the manual IP section isn't essential
manual_ip:
# Set this to the IP of the ESP
static_ip: 192.168.1.14
# Set this to the IP address of the router.
gateway: 192.168.1.1
# The subnet of the network.
subnet: 255.255.255.0

ap:
ssid: "oil-hotspot"
password: ""

mdns:

captive_portal:
# the portal is useful when the hotspot is active because wifi failed

output:
- platform: gpio
pin: GPIO2
id: gpio_2blue
# there is an on board LED I use to signal that wifi is connected


switch:
- platform: restart
name: ${devicename} restart


interval:
- interval: 5s
then:
if:
condition:
wifi.connected:
then:
- output.turn_on: gpio_2blue
- delay: 2s
- output.turn_off: gpio_2blue
- delay: 2s
else:
- output.turn_off: gpio_2blue



uart:
rx_pin: GPIO16 # my ORANGE > green at the sensor
tx_pin: GPIO17 # my YELLOW > blue at the sensor
# if the sensor doesn't work simply reverse the rx tx connections in the code above
# red at the sensor 5v VCC black at sensor GND
baud_rate: 9600


sensor:

# a02yyuw configuration

- platform: "a02yyuw"
name: "oil-level"
accuracy_decimals: 0
unit_of_measurement: "L"
id: myoillevel
filters:
- throttle: 20s
- lambda: return x * -1 ;
# in my tank 100mm = 100 litres
# - sliding_window_moving_average:
# window_size: 5
# send_every: 10
state_class: total
device_class: volume


- platform: wifi_signal
name: ${devicename} wifi signal
update_interval: 120s

- platform: internal_temperature
name: "intern-temperature"
filters:
- lambda: return x -30 ;

# IF YOU HAVE A DHT SENSOR USE IT SO:
- platform: dht
pin: GPIO33 # ORANGE
model: DHT11
temperature:
name: "boilerroom temperature"
update_interval: 300s


time:
- platform: homeassistant
id: homeassistant_time

# WEBSERVER ISN'T NECESSARY
web_server:
port: 80
include_internal: true
version: 3

# DIAGNOSTIC INFO ON WIFI
text_sensor:
- platform: wifi_info
ip_address:
name: ${devicename} ip
ssid:
name: ${devicename} ssid
mac_address:
name: ${devicename} mac
scan_results:
name: ${devicename} scan



add your sensor data to the Home Assistant overview

  • when the code is installed, power-up the ESP board with a USB power source and go to Home Assistant > Integrations > + > ESPHome. Your device will be ‘discovered’ or else you might have to enter the IP address used in the code. You’ll then see the oil level device that has been added to Home Assistant. The device will have an entity named like sensor.oil-level
  • go to the Home Assistant Overview where your stuff is normally displayed. Choose Edit dashboard in the top corner.
  • add a new card called history graph. On the entity line select your sensor.oil-level
  • add a new card called gauge to display your oil level. On the entity line select your sensor.oil-level
a sensor card; a history graph card and a gauge card. notice that the ‘oil level’ is INCREASING. However if you used my line of code (- lambda: return x * -1) the oil_level will be a negative number. That’s better because the graph should FALL.
The level shown is the amount of oil we’re short of – the amount needed to fill the tank!

a few issues:

After several months use I needed to address some issues. Because of these points I modified the code as shown below. You may want to substitute the above ‘sensor:’ section with the following ‘sensor:’ section (explained below)

  • calibration: the sensor measures in metres so I have to calculate the litres. My tank has a perfectly regular shape from top to bottom – so by measuring dipstick depths, I found that 100cm of tank depth contains 105.3 litres. In the code below the last two lines (filter and lamda) do this calibration. The two lines can be edited or entirely omitted to suit your tank.
  • if your readings are a bit noisy counteract this with a sensor filter such as the sliding average of an oil level reading.
  • it was suggested that the ‘oil used’ graph should fall, not rise, so I made the reading negative. This also makes it easier to know how much oil to order. I should rename the sensor ‘oil used’ because the number it returns is the amount of oil I need to buy to fill the tank. Next I really don’t need an oil level reading every 10 seconds so I increased the update interval. The commercially available FoxRadar takes only a few readings per day.
  • to turn your readings into KWh multiply the litres by 9 – see my example from another sensor here
# add a filter to the sensor section to calibrate the sensor.

# add a negative sign to produce a falling oil level:
# filters:
# - lambda: return x * -1053;

# note: 1053 is 1.053 (fiddle factor for tank) * 1000 (convert mm to litres)

# add a sensor filter to remove noise:

filters:
- lambda: return x * 1053;
- sliding_window_moving_average:
window_size: 20
send_every: 10

# if your tank shape is irregular you can put your calibration graph of distance and volume in the code. I might have improved the filter section so:

# – calibrate_linear:
# – 110 -> 0
# – 95 -> 204
# – 75 -> 544
# – 55 -> 900
# – 35 -> 1320
# – 15 -> 1660
# – 0 -> 1800

when do I need to order more oil?

The first nice consequence is that I now know how much oil I need to order and how much I use. We might now need to predict the date when we need to order more oil and get notified – see how I calculate when I need to order more oil using Home Assistant. Also I might need to store our oil use in a spreadsheet as well as record the outside temperature – see send sensor data from Home Assistant to a spreadsheet

In cold December two households use 15 to 30 litres a day. So I would need to order the tank level plus at least an extra 9 * 15 = 135 litres as it will take say, 9 days to arrive.

If you’re more interested in water tank levels not oil tank levels:

water level graphs. Noisey time of flight sensor
I used the same sensor on my WATER (not oil) tank – see here for the housing I used

Leave a Reply

Your email address will not be published. Required fields are marked *