One additional project is to measure water level in tank (and switch either well pump or pump in tank depending on whether there is water or no). Originally, I went for JSN-SR04T ( https://www.aliexpress.com/item/1005001431443682.html?spm=a2g0o.order_list.order_list_main.62.603e1802T3HPNJ ), however I was not able to get it to measure precisely, not to mention longer distances (it is advertised as up to 4m, I was not able to get it to measure above 2m).
Anyway, I purchased VL53L1X TOF400C ( https://www.aliexpress.com/item/1005003614683022.html?spm=a2g0o.order_list.order_list_main.50.603e1802T3HPNJ ). As seen in the picture, it does require some extra work to make it waterproof, but that should not be a big deal.
Since it is not natively supported by ESPHome (VL53L0X is), it took a moment to gather the right resources. I am using Wemos D1 mini. Wiring is relatively simple - sensor is powered by 3,3V (from wemos), GND, and SDA and SCL (see below config).
yaml for the device:
substitutions:
devicename: laser-distance
esphome:
name: '${devicename}'
includes:
- tof_vl53l1x.h
libraries:
- "Wire"
- "VL53L1x"
esp8266:
board: esp01_1m
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "xxx"
ota:
password: "xxx"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Laser-Distance Fallback Hotspot"
password: "xxx"
captive_portal:
i2c:
sda: GPIO4
scl: GPIO5
scan: false
frequency: 400kHz
sensor:
- platform: custom
lambda: |-
auto my_VL53L1X_sensor = new VL53L1XCustomSensor();
my_VL53L1X_sensor->set_update_interval(2000); // define update interval
App.register_component(my_VL53L1X_sensor);
return {my_VL53L1X_sensor};
sensors:
name: "Distance"
accuracy_decimals: 0
unit_of_measurement: "cm"
id: distance
filters:
- lambda: return x/10 ;
- median:
window_size: 15
send_every: 15
send_first_at: 15
- platform: template
name: "Filled Tank %"
lambda: return id(distance).state;
unit_of_measurement: "%"
accuracy_decimals: 0
filters:
- calibrate_linear:
- 1 -> 100
- 80 -> 0
As seen, I convert measurement to cm instead of mm. In addition, template sensor is to get tank % filled. It requires setting limit values accordingly.
In order to compile, put additional file next to yaml for the device called tof_vl53l1x.h
with following content:
#include "esphome.h"
#include <Wire.h>
#include <VL53L1X.h>
class VL53L1XCustomSensor : public PollingComponent, public Sensor {
private:
VL53L1X tof_sensor;
public:
// constructor
VL53L1XCustomSensor() : PollingComponent(15000) {} // polling every 15s
void setup() override {
// This will be called by App.setup()
Wire.begin();
Wire.setClock(400000); // use 400 kHz I2C
tof_sensor.setTimeout(500);
tof_sensor.setAddress(0x29);
if (!tof_sensor.init()) {
ESP_LOGE("VL53L1X custom sensor", "Failed to detect and initialize sensor!");
return;
}
tof_sensor.setDistanceMode(VL53L1X::Long);
tof_sensor.setMeasurementTimingBudget(250000); // 1000us = 1ms
ESP_LOGI("VL53L1X custom sensor", "initialised");
//tof_sensor.startContinuous(250); // ms
}
void update() override {
//uint16_t distance_mm = tof_sensor.read(false);
uint16_t distance_mm = tof_sensor.readSingle();
if (!tof_sensor.timeoutOccurred()) {
publish_state(distance_mm);
} else {
ESP_LOGE("VL53L1X custom sensor", "Timeout during read().");
}
}
};