Pi Pico 2 Automatic Pump Project

Afternoon,

I have a project I am working on to remove water from my house when it rains a lot using a pump and creating a python action to remove surface water. I’m looking to use a Pi Pico 2 and a Grove - Water Level Sensor (10cm) for Arduino I just have some questions about the sensor.

  1. The water I am reading may contain soil and maybe not clean water. Will this sensor read accurately in this scenario?

  2. The electronics are not waterproof is there a way to protect the electronic from splashing water? I have a small plastic box containing toothpicks I can modify to enclose only the electronic in. Attached image that may keep the water out.?

  3. The sample code is in C I would like to use micro python so I have with the help of Gemini Ai converted it to micro python code for Pico

import time


# Grove - Water Level Sensor addresses
ATTINY1_HIGH_ADDR = 0x78
ATTINY2_LOW_ADDR = 0x77


# I2C configuration
i2c = I2C(scl=Pin(22), sda=Pin(21))  # Adjust pins as needed


# Threshold for water detection (adjust as necessary)
THRESHOLD = 100


def read_sensor_data(address):
    """Reads data from the specified sensor address."""
    try:
        # Read 12 bytes from the high address sensor
        if address == ATTINY1_HIGH_ADDR:
            data = i2c.readfrom_mem(address, 0x01, 12)
        # Read 8 bytes from the low address sensor
        elif address == ATTINY2_LOW_ADDR:
            data = i2c.readfrom_mem(address, 0x01, 8)
        else:
            return None
        return data
    except OSError:
        print(f"Error reading from sensor at address: {hex(address)}")
        return None


def calculate_water_level():
    """Calculates the water level based on sensor readings."""
    touch_count = 0


    high_data = read_sensor_data(ATTINY1_HIGH_ADDR)
    low_data = read_sensor_data(ATTINY2_LOW_ADDR)


    if high_data is None or low_data is None:
        return None


    for value in high_data:
        if value > THRESHOLD:
            touch_count += 1


    for value in low_data:
        if value > THRESHOLD:
            touch_count += 1


    # Calculate percentage (adjust range as needed)
    water_level = (touch_count / 20) * 100  # 20 total sensor points


    return water_level


while True:
    try:
        water_level = calculate_water_level()
        if water_level is not None:
            print(f"Water Level: {water_level:.2f}%")
        time.sleep(1)  # Read every second
    except Exception as e:
        print(f"An error occurred: {e}")
        time.sleep(5)  # Wait before retrying




—-------------------------------------------------------------------------------------------------------
Explanation:
1. Import necessary libraries:

   * machine: Provides access to hardware peripherals like I2C.
   * time: For introducing delays.
   2. Define sensor addresses:

      * ATTINY1_HIGH_ADDR and ATTINY2_LOW_ADDR: Store the I2C addresses of the two sensors.
      3. Configure I2C:

         * i2c = I2C(scl=Pin(22), sda=Pin(21)): Initializes the I2C object with the appropriate pins. Adjust these pin numbers based on your Pico's wiring.
         4. read_sensor_data(address) function:

            * Reads data from the specified sensor address.
            * Handles potential OSError during I2C communication.
            5. calculate_water_level() function:

               * Reads data from both sensors.
               * Counts the number of sensor points exceeding the THRESHOLD.
               * Calculates the water level percentage based on the count.
               * Adjust the calculation based on the number of sensor points and desired percentage range.
               6. Main loop:

                  * Continuously reads and calculates the water level.
                  * Prints the water level with two decimal places.
                  * Includes basic error handling to catch unexpected exceptions.
To use this code:
                  1. Connect the Grove - Water Level Sensor to your Pico using I2C.
                  2. Adjust the scl and sda pins in the i2c initialization to match your wiring.
                  3. Adjust the THRESHOLD value based on your sensor readings and desired sensitivity.
                  4. Adjust the water level calculation in the calculate_water_level() function if needed.
                  5. Upload the code to your Pico using Thonny or another suitable tool.
This code provides a basic framework for reading data from the Grove - Water Level Sensor on the Raspberry Pi Pico. You can further enhance it by adding features like:
                  * More robust error handling and recovery mechanisms.
                  * Data logging to a file or sending data to a remote server.
                  * Implementing alarms or notifications based on water level thresholds.
                  * Using a graphical display to visualize the water level.
                  * Calibrating the sensor for more accurate readings.
Remember to consult the Grove - Water Level Sensor documentation and the Raspberry Pi Pico documentation for more detailed information.
Grove - Water Level Sensor (10cm) for Arduino








—-----------------------------------------------------------------------------------------------------------
Update for calibration 


from machine import I2C, Pin
import time


# Grove - Water Level Sensor addresses
ATTINY1_HIGH_ADDR = 0x78
ATTINY2_LOW_ADDR = 0x77


# I2C configuration
i2c = I2C(scl=Pin(22), sda=Pin(21))  # Adjust pins as needed


# Calibration variables
MIN_SENSOR_COUNT = 0  # Sensor count at empty tank
MAX_SENSOR_COUNT = 20  # Sensor count at full tank


def read_sensor_data(address):
    """Reads data from the specified sensor address."""
    try:
        # Read 12 bytes from the high address sensor
        if address == ATTINY1_HIGH_ADDR:
            data = i2c.readfrom_mem(address, 0x01, 12)
        # Read 8 bytes from the low address sensor
        elif address == ATTINY2_LOW_ADDR:
            data = i2c.readfrom_mem(address, 0x01, 8)
        else:
            return None
        return data
    except OSError:
        print(f"Error reading from sensor at address: {hex(address)}")
        return None


def calculate_water_level():
    """Calculates the water level based on sensor readings."""
    touch_count = 0


    high_data = read_sensor_data(ATTINY1_HIGH_ADDR)
    low_data = read_sensor_data(ATTINY2_LOW_ADDR)


    if high_data is None or low_data is None:
        return None


    for value in high_data:
        if value > 100:  # Adjust threshold as needed
            touch_count += 1


    for value in low_data:
        if value > 100:  # Adjust threshold as needed
            touch_count += 1


    # Calculate water level using calibration
    water_level = ((touch_count - MIN_SENSOR_COUNT) / 
                   (MAX_SENSOR_COUNT - MIN_SENSOR_COUNT)) * 100


    return water_level


# Calibration procedure
def calibrate_sensors():
    global MIN_SENSOR_COUNT, MAX_SENSOR_COUNT


    print("Place the sensor in an empty tank.")
    input("Press Enter when ready...")
    MIN_SENSOR_COUNT = _get_sensor_count()


    print("Place the sensor in a full tank.")
    input("Press Enter when ready...")
    MAX_SENSOR_COUNT = _get_sensor_count()


    print(f"Calibration complete:\n"
          f"MIN_SENSOR_COUNT: {MIN_SENSOR_COUNT}\n"
          f"MAX_SENSOR_COUNT: {MAX_SENSOR_COUNT}")


def _get_sensor_count():
    """Helper function to get the current sensor count."""
    count = 0
    for _ in range(10):  # Average readings over 10 samples
        count += calculate_water_level()
        time.sleep(0.1)
    return int(count / 10)


# Run calibration once
calibrate_sensors()


while True:
    try:
        water_level = calculate_water_level()
        if water_level is not None:
            print(f"Water Level: {water_level:.2f}%")
        time.sleep(1)  # Read every second
    except Exception as e:
        print(f"An error occurred: {e}")
        time.sleep(5)  # Wait before retrying




—-----------------------------------------------------------------------------------------------------
Key Improvements:
                  * Calibration:
                  * The code now includes a calibrate_sensors() function to determine MIN_SENSOR_COUNT and MAX_SENSOR_COUNT.
                  * During calibration, the user is prompted to place the sensor in an empty tank and then in a full tank.
                  * The _get_sensor_count() helper function averages multiple readings for more accurate calibration values.
                  * Water Level Calculation:
                  * The calculate_water_level() function uses the calibrated MIN_SENSOR_COUNT and MAX_SENSOR_COUNT to calculate the water level percentage.
                  * Clarity:
                  * Comments and variable names are improved for better readability.
To use this code:
                  1. Connect the Grove - Water Level Sensor to your Pico using I2C.
                  2. Adjust the scl and sda pins in the i2c initialization to match your wiring.
                  3. Run the code. The program will guide you through the calibration process.
                  4. After calibration, the code will continuously monitor and display the water level.
This refined code provides a more accurate and robust solution for water level measurement by incorporating calibration into the process.
  1. Taking this information into account do you have any input to improve the success of the project?

Big Thank you if you have got this far and thank you if you give me some feedback.

Peter

Hi Peter
THIS ONE FOR CORE TOO.
Check the hardware overview pictures. The connector designations do not agree.They are mirror image.
According to the schematic pins 1 & 2 are I2C, Pin 3 is VCC and pin 4 is Gnd.

This would agree with the bottom Pic although it tends to throw a bit of doubt on the whole thing.
Cheers Bob

1 Like

Thinking about the consequences if this system fails to cut in. Is your house or basement going to flood?
Have you considered a submersible sump pump with a float switch. What is your reasoning behind this more interesting but complex solution?

1 Like

Hi @Robert93820,

Thanks for bringing this to our attention. I have tested this sensor and the pinout shown in this image is the correct version.

It seems like there has been an error when printing these boards as the writing on the bottom side of the board indicates a mirrored, incorrect pinout.

I have raised this issue with the manufacturer but in the mean time the pinout I have described above should be correct and connecting a standard grove cable to this module will ensure the correct connections.

Hey @Peter250114,

For making things “kind of” waterproof, I have had luck in the past by using a small enclosure box like the one you have and sealing any openings with hot glue. I doubt this would continue to be waterproof if any pressure was applied but this should work for general splashing and light water exposure.

I second what @David191372 has mentioned. Considering that this could result in a fair amount of damage if this system failed it may be best to consider a prebuilt option instead of the DIY approach.

Hope this helps!

Hi Samuel.
This means that the schematic is also incorrect. That IS a bad blunder. I for one would believe the schematic and the other image. Just for the reason that if 2 out of 3 are the same the odds are that this would be correct and the other one wrong.
In this case it would seem that the 2 out of 3 are incorrect and the odd one out is OK. I find it a bit hard to comprehend that such an error could occur in 2 fairly unrelated cases. By unrelated I mean that one is a schematic presumably drawn by the design people and one is a photo (I think).
Cheers Bob

Hi @Robert93820

I’ve just tested one of our shelf stock and there is no error with the board, the solder pads on the back of the board do not match the front of the board and are flipped 180 from where you would expect them to be.

Hi Dan
You might check the schematic also. I might be seeing double or something but this seems to be wrong also.
Cheers Bob