Water Level Sensor

I’m looking to use this for my hydroponics system to monitor water level in a bucket. However, it doesn’t have any python code listed. Is there anyone who has started writing this and would like to share or point me in the right direction?

Hi @vondalej, which sensor you are using?

From the Grove - Water Level Sensor WiKi page it shows only Arduino library is completed. @Baozhu any updates on this.

Capture

Not yet, I’m sure we’ll have an update in the coming months.

2 Likes

That’s great :slightly_smiling_face::+1:

Any movement on getting this written??

Hi there,

I’m also interested in working with this sensor in Python. Anyone tried this already?

Actually, I just tried it. My code seems to work, but at some point it showed “Remote I/O error” (I’m not sure if I might have induced the error by accidentally touching the wires on the breadboard, though)

I had to compile the micropython library on my Pi: https://www.raspberrypi.org/forums/viewtopic.php?t=191744

Please see the code and the screenshots:

import time
import smbus
import numpy as np

NO_TOUCH = 0xFE
THRESHOLD = 100
ATTINY1_HIGH_ADDR = 0x78
ATTINY2_LOW_ADDR = 0x77

i2c_ch = 1
i2c_address1 = 0x77
i2c_address2 = 0x78

# Register addresses -- don't know what they are for
reg_temp = 0x00
reg_config = 0x01 # offset?

bus = smbus.SMBus(i2c_ch)

def getHigh12SectionValue():
    high_data = bus.read_i2c_block_data(ATTINY1_HIGH_ADDR, reg_config, 12)
    return high_data

def getLow8SectionValue():
    low_data = bus.read_i2c_block_data(ATTINY2_LOW_ADDR, reg_config, 8)
    return low_data
    
def check_water_level():
    sensorvalue_min = int(250)
    sensorvalue_max = int(255)
    low_count = int(0)
    high_count = int(0)
    
    touch_val = int(0)
    trig_section = int(0)
    low_count = 0
    high_count = 0
    
    low_data = getLow8SectionValue()
    high_data = getHigh12SectionValue()
    
    for i in range(8):
        if low_data[i] > THRESHOLD:
            touch_val += 1
       
    for i in range(12):
        if high_data[i] > THRESHOLD:
            touch_val += 1
    
    value = touch_val * 5
    print("water level = " + str(value) + "%")


while True:
    check_water_level()
    time.sleep(2)

Here’s a short video on how my code works:

Here’s the error message I got in the end, but now the code runs for a few minutes and nothing happens - so it probably was by accident:

I believe my code lacks some sensor diagnostics, e.g. if the bus actually could be read, or - I’m not using the NO_TOUCH variable, which probably determines some sensor parameters or readouts. I did not figure out how to use it from the Arduino code. If you would have any ideas on how to improve this, please share :slight_smile:

1 Like

Hi @mormegil6
WaW!Very good python code, can I update this code to our Wiki?
(I will sign your name for thank you.)
The OSError: [Errno 121] Remote I/O error offer occurred when the external hardware cannot be found, so you may not have the I2C permission, or the I2C address setting is incorrect, or the wiring is bad.

1 Like

Thanks @jiachenglu :slight_smile:

I am not sure if the code is that good - I think it could be smoother without the for loops, and use vector operations instead. My code might be polished a bit in this regard. Sure, you might use this code for the Wiki as it is right now, or you might wait for the polished version :wink:

Generally, some parts of code could be shorter, but I wanted my code to resemble the Arduino code as much as possible.
Furthermore, the part where I am declaring reg_temp and reg_config variables - I have found them in some other Python example regarding reading raw data from I2C bus (which was about the temperature sensor, hence reg_temp). I am also quite unsure about the meaning reg_config variable - from what I read in the documentation of the function it’s used, read_i2c_block_data(), the second value this function accepts is “offset”.
Additionally, I forgot to remove some unused variables and unused references, ie. i2c_address1 and i2c_address2, which are duplicates of ATTINY2_LOW_ADDR and ATTINY1_HIGH_ADDR. Also, I am not using the numpy library; I was considering using it but in its current shape it’s not needed.

Hi @mormegil6
Thanks for your python code, I followed the steps to build micropython and got the below output.
By the way, we are waiting for your polished version.
water

Hi @jiachenglu,
Sorry for the long time without a reply. I was extremely busy for the past 2 weeks, and I still am but not for long. I hope to get back to this code by the end of this week :slight_smile:

Hello @jiachenglu,
Sorry for the time it took. I reviewed my code, and I deleted unused variables etc. I did leave the for loops. I believe they can be done in a more fancy way ie. using vector logic, but I think they work quite straight-forward and they don’t need such fanciness.
Here, you can post this code on your Wiki page for Raspberry Pi / Python:

import time
import smbus
import numpy as np

NO_TOUCH = 0xFE # unused variable
THRESHOLD = 100
ATTINY1_HIGH_ADDR = 0x78
ATTINY2_LOW_ADDR = 0x77

i2c_ch = 1

reg_temp = 0x00 # register address -- temperature? / Unused variable
reg_config = 0x01 # register address -- offset?

bus = smbus.SMBus(i2c_ch)

def getHigh12SectionValue():
    high_data = bus.read_i2c_block_data(ATTINY1_HIGH_ADDR, reg_config, 12)
    return high_data
    
def getLow8SectionValue():
    low_data = bus.read_i2c_block_data(ATTINY2_LOW_ADDR, reg_config, 8)
    return low_data
    
def check_water_level():
    touch_val = int(0)
    
    low_data = getLow8SectionValue()
    high_data = getHigh12SectionValue()
    
    for i in range(8):
        if low_data[i] > THRESHOLD:
            touch_val += 1
        
    for i in range(12):
        if high_data[i] > THRESHOLD:
            touch_val += 1
        
    value = touch_val * 5
    print("water level = " + str(value) + "%")
	return value / 100

while True:
    sensorLevel = check_water_level()
    return sensorLevel
	time.sleep(2)

One more thing - I have made a little script that logs the sensor data. It was logging the water level with 5min time gap between readouts. I have noticed occasional spikes in the water level read. It should always show 0%, but sometimes it shows 5%, or even 60%: