from machine import Pin, I2C
import ssd1306
import time
# ESP32 Pin assignment
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)
# Original tank dimensions (inches)
original_tank_height = 52 # Original height of the tank in inches
original_tank_width = 41 # Original width of the tank in inches
# Conversion factor for inches to centimeters (1 inch = 2.54 cm)
inches_to_cm = 2.54
# Convert original dimensions to centimeters
max_tank_height_cm = original_tank_height * inches_to_cm # Convert height to cm
max_tank_width_cm = original_tank_width * inches_to_cm # Convert width to cm
# Tank parameters for display (scaled for visual representation)
tank_x = 10
tank_y = 5 # Position tank slightly higher for visibility
tank_width = 30 # Graphical width for display
tank_height = 50 # Graphical height for display
# Ultrasonic sensor pins
TRIG_PIN = 19
ECHO_PIN = 18
# Set up pins for ultrasonic sensor
trigger = Pin(TRIG_PIN, Pin.OUT)
echo = Pin(ECHO_PIN, Pin.IN)
# Variables to track fill rate
previous_water_level = 0
previous_time = time.time() # Get current time in seconds
fill_rates = [] # List to store fill rates for averaging
def measure_distance():
# Send a 10us pulse to trigger
trigger.value(0) # Set trigger LOW
time.sleep_us(2)
trigger.value(1) # Set trigger HIGH
time.sleep_us(10)
trigger.value(0) # Set trigger LOW
# Measure the duration of the echo pulse
pulse_start = 0
pulse_end = 0
while echo.value() == 0:
pulse_start = time.ticks_us()
while echo.value() == 1:
pulse_end = time.ticks_us()
# Calculate the distance in cm (speed of sound is 34300 cm/s)
pulse_duration = time.ticks_diff(pulse_end, pulse_start)
distance = (pulse_duration * 0.0343) / 2 # cm
return distance
def draw_tank(water_level):
global previous_water_level, previous_time, fill_rates # Access global variables
# Clear the screen
oled.fill(0)
# Draw the tank outline (visual representation)
for x in range(tank_width):
oled.pixel(tank_x + x, tank_y, 1) # Top
oled.pixel(tank_x + x, tank_y + tank_height, 1) # Bottom
for y in range(tank_height):
oled.pixel(tank_x, tank_y + y, 1) # Left
oled.pixel(tank_x + tank_width - 1, tank_y + y, 1) # Right
# Draw the water
water_fill_height = int((water_level / max_tank_height_cm) * tank_height)
for h in range(water_fill_height):
for x in range(1, tank_width - 1):
oled.pixel(tank_x + x, tank_y + (tank_height - 1 - h), 1) # Fill water
# Calculate percentage
percentage = (water_level / max_tank_height_cm) * 100
# Calculate current fill rate
current_time = time.time()
elapsed_time = current_time - previous_time
if elapsed_time > 0: # Avoid division by zero
current_fill_rate = (water_level - previous_water_level) / elapsed_time
# Only consider fill rates that are positive and store them for averaging
if current_fill_rate > 0:
fill_rates.append(current_fill_rate)
# Keep only the last 5 fill rates for smoothing
if len(fill_rates) > 5:
fill_rates.pop(0)
else:
current_fill_rate = 0
# Estimate remaining time based on average fill rate
if fill_rates:
average_fill_rate = sum(fill_rates) / len(fill_rates)
remaining_fill_height = max_tank_height_cm - water_level
if average_fill_rate > 0:
remaining_time = remaining_fill_height / average_fill_rate
else:
remaining_time = float('inf') # If not filling, indicate it
else:
remaining_time = float('inf') # No fill rates available
# Convert remaining time to minutes and seconds
if remaining_time != float('inf'):
minutes = int(remaining_time // 60)
seconds = int(remaining_time % 60)
else:
minutes = 0
seconds = 0
# Display compact text on the right
oled.text('Tank', 50, 5)
oled.text('Lvl: {:.0f}%'.format(percentage), 50, 20)
oled.text('T: {}m {}s'.format(minutes, seconds), 50, 35)
oled.show()
# Update previous values for the next iteration
previous_water_level = water_level
previous_time = current_time
# Main loop for measuring and displaying water level
while True:
distance = measure_distance() # Get distance from the ultrasonic sensor
water_level = max(0, max_tank_height_cm - distance) # Calculate water level based on distance
draw_tank(water_level) # Display the current water level
time.sleep(1) # Update every second