Jessica nailed the main issue: at 15-20 cm you’re inside the blind zone. Mount it higher, a short PVC pipe section as a stand-off works, so full tank is at least 30 cm away.
Second issue is the Python timing. Busy-wait loops on a Pi 3 miss edges whenever the scheduler steps in. Use gpiozero with the pigpio pin factory, it timestamps edges in the daemon:
from gpiozero import DistanceSensor
from gpiozero.pins.pigpio import PiGPIOFactory
import statistics, time
s = DistanceSensor(echo=24, trigger=23, max_distance=4.5,
pin_factory=PiGPIOFactory())
def level_cm():
vals = []
for _ in range(7):
vals.append(s.distance * 100); time.sleep(0.1)
return statistics.median(vals)
Median of 7 throws away the odd echo off the tank wall. Then send {"distance_cm": d, "level_pct": ...} as numbers and put an alarm rule on level_pct below 20 with a debounce of 3 readings, so one bad echo doesn’t wake the warden.

