calibrate a ‘Vl53L0X time of flight sensor’ to measure water or oil tank level
a tank level sensor that’s more useful than anything you can buy. This post shows my housing for a sensor that measures oil and water levels. The sensor is a VL53L0X time of flight sensor. If you just want to see how to get readings from the Vl53L0X sensor, see this post instead. Alternatively see my very similar oil tank level sensor which uses the ultrasonic sensor JSN-SR04T
what you need for this
- an infrared based Vl53L0X time of flight sensor (~£5 ebay)
- project box for sensor 83mm x 58 mm x 33mm IP66 waterproof ABS enclosure / clear cover
- project box for ESP 63mm x 58 mm x 35mm IP66 waterproof ABS enclosure / clear cover
- any ESP32 or ESP8266 development board with wifi. I used a nodemcu v3 ESP8266 (~ £6). If you need to use battery power an ESP8266 might be more appropriate than an ESP32 board. The battery power might be 6 x 18650 cells based on this one I made
- ESPhome and Home Assistant to create the code, collect readings and display the data.
- USB wire cut and extended to whatever length is needed. I used coloured silicone-covered wire 18 AWG 0.75mm copper conductor.
about the sensor
The Vl53L0X time of flight sensor works by sending infrared blips to a liquid surface and then measuring the ‘time of flight’ to estimate how far away it is. You can find variations of this sensor (VL53L0X, TOF10120, VL53L1X, VL6180X) which work best at different distances (diagram). I chose the Vl53L0X because it’s made for the range 30mm-1200m as suits my tank. The software can also set it in a long distance remote range of 1500 -2000mm. Wonderfully, when the sensor is hooked up it sends a distance value (in metres) and I can multiply that by a number to get readings in mm or litres or kW or even money. The calculation is simple – if your oil tank has an irregular shape I’ve included the code for that below – anything is doable.
wiring the VL53L0X tank level sensor and ESP
The Vl53L0X module has six pin connectors – you need to use four of them. I use Dupont male to female wires because my ESP8266 nodemcu already had pins. I soldered the male pins to the Vl53L0X module and extended the wires with coloured cables (silicone 18 AWG 0.75mm) and covered the join in heat-shrink.
how to protect the components from a damp, wet environment
Getting dirt in the tiny emitter and sensor holes is to be avoided as the emerging pulse or photon can be deflected randomly / cause crosstalk. My sensor and ESP8266 will be in a tank in a loft so I bought a project box and glued the sensor to its transparent lid. The sensor will be attached facing downwards from the plastic tank lid. The pictures show this. I happened to have some heavy duty Velcro hook & loop tape to help fix the boxes. The ESP8266 has been given its own box – so as not to put all eggs in one basket. Also, in case of failure I’ll be able to replace one or other component.
You can protect the sensor with glass, perspex or polycarbonate. The cover should be as thin, flat, parallel, clear and fitted close to the sensor as possible. ST, the chip maker have a video explaining how a more fussy two-piece glass cover pretty much reduces the crosstalk due to dust. I so wish they’ll create a similarly protected chip. The sensor notes are here.
My oil tank sensor (below) uses a different fitting to the water tank sensor above. A 3D printed part holds the sensor in place with the help of some hot glue. I don’t yet know if the vapour from the oil will damage the VL53L0X so I’m looking to improve this it it fails. I cut a 30mm circle of acetate film (from a phone case) and glued it to the cap I’d made for the sensor.
The sensor needs to be fixed so that it points down at the surface of the oil in the tank (photo). I used a tank hole that had housed the dipstick. A suitable cap, as shown below, was made on a 3D printer. A container cap might have worked … as long as it doesn’t wobble and thus affect the readings. You might instead drill a hole for it but I’ve no advice on this.
calibrating the sensor
When ESPhome is installed on the ESP8266 (this post) I receive readings in mm which is perfect! However wary that I’ve obscured the sensor with a clear plastic cover, I made a calibration graph of readings vs actual distance. As you see in the graph below that’s only slightly necessary. The graph intercept is at 34mm so I may subtract that from each reading and multiply the result by 1.05. As of Nov 2022 the code is as follows.
adjust the code to calibrate the sensor
# BEFORE CALIBRATION WATER SENSOR - THIS CODE WORKS sensor: - platform: vl53l0x name: "watertank-tof" address: 0x29 update_interval: 10s long_range: false accuracy_decimals: 0 unit_of_measurement: "mm" id: watertanklevel filters: - lambda: return x * 1000; # AFTER CALIBRATION WATER SENSOR - WORKING CODE sensor: - platform: vl53l0x name: "watertank-tof" address: 0x29 update_interval: 10s long_range: false accuracy_decimals: 0 unit_of_measurement: "mm" id: watertanklevel filters: - lambda: return (x - 0.034) * -1050; # calculation: 34 is the graph intercept so that's - 0.034 in metres x a scaling factor found on graph. Make the value negative so that the graph will drop not rise as the tank empties.