Liquid level measurement is the process of determining the level of a liquid in a tank or other container. There are many different ways to measure liquid level, and the specific method used will depend on the application and the requirements of the system.
Some common methods for measuring liquid level include:
The specific type of liquid level measurement system that is best suited for a particular application will depend on factors such as the size of the tank, the accuracy required, and the environmental conditions.
It is possible to build a water level measurement system that uses an ESP32 microcontroller and a smartphone. The ESP32 is a low-cost, low-power microcontroller that is widely used for building Internet of Things (IoT) devices and other connected projects. It has a built-in Bluetooth module and a variety of input/output (I/O) pins that can be used to connect sensors, actuators, and other devices.
To build a water level measurement system based on the ESP32 and a smartphone, you will need to connect a sensor to the ESP32 that is capable of measuring the water level. Some options for water level sensors include float switches, ultrasonic sensors, pressure sensors, and conductivity sensors.
Once the sensor is connected, you can use the ESP32 to read the sensor data and send it to a smartphone via Bluetooth. You can then use an app on the smartphone to display the water level data and potentially control the system, such as by activating a pump or valve based on the water level.
The specific steps for building a water level measurement system based on the ESP32 and a smartphone will depend on the specific sensor and components you are using, as well as the code you write in the ESP32 development environment.
In this project, we will build a smartphone-based bottle water level measurement system using the ESP32 board.
Our proposed work will be easy for real-time liquid level measurement using Bluetooth wireless technology.
This is why we will create two programs: a mobile application with App Inventor for the smartphone and a program for the ESP32 board.
We know that water, like any other liquid, is a conductor of electric current.
The detection of the level of water filled in the bottle is based on this idea.
When the water level rises, this liquid comes into contact with the end of the connection wire fixed in the bottle, the electrical circuit is then closed and a very low voltage electrical current is detected by the ESP32 board.
When the water level drops, the electrical circuit is open. As a result, there is no more electric current.
Then the ESP32 board sends this information to the Smartphone via Bluetooth.
ESP32 card
An ESP32 card is a type of hardware that is based on the ESP32 microcontroller. The ESP32 is a low-cost, low-power microcontroller that is widely used for building Internet of Things (IoT) devices and other connected projects. It has a built-in Wi-Fi module and a variety of input/output (I/O) pins that can be used to connect sensors, actuators, and other devices.
Bottle
4 resistors of 10Kohm
A resistor is an electronic component that is used to resist the flow of electrical current. It is made of a material that has a specific resistance value, which determines how much the resistor will resist the flow of current.
Resistors are used in a variety of electronic circuits to control the flow of current and to adjust the voltage levels in a circuit. They are often used in conjunction with other components, such as capacitors and inductors, to create more complex circuits.
test plate
A test plate is a type of device used in robotics to test the functionality and performance of various components or systems. It is typically a physical platform or structure that is designed to hold and support various test items or devices, such as sensors, actuators, motors, or other types of mechanical or electrical components. Test plates can be used to simulate different environments or conditions, such as temperature, humidity, vibration, or other factors, in order to evaluate the performance of the components or systems being tested. They can also be used to perform a variety of diagnostic or diagnostic tests, such as stress testing, endurance testing, or other types of evaluations.
connecting wires
Wires are used to transmit electrical signals and power to various components such as motors, sensors, and microcontrollers. It’s important to properly route and secure the wires to prevent tangles and damage. There are several methods for doing this, including using cable ties, clamps, and wire looms. It’s also a good idea to use different colors or labeling to identify the different wires and their functions. When connecting wires in a robot, it’s important to follow proper safety procedures, such as using the correct wire stripper and connectors, and wearing protective equipment such as gloves and safety glasses.
First We drill 5 holes in the bottle. Then we fix a connection wire in each hole.
Then we connect:
the lowest jumper wire to the 3.3V pin of ESP32
connecting the 3rd wire to pin D32 of ESP32
connecting the 4th wire to pin D35 of ESP32
the 5th jumper wire to pin D34 of ESP32
Here are the micropython programs that can detect the level of water filled in the bottle and send this information to the Smartphone via Bluetooth.
esp32-water-level.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
from esp_ble_uart import * import time from machine import Pin, ADC from machine import freq #freq(160000000) level_1 = ADC(Pin(33)) level_1.atten(ADC.ATTN_11DB) level_2 = ADC(Pin(32)) level_2.atten(ADC.ATTN_11DB) level_3 = ADC(Pin(35)) level_3.atten(ADC.ATTN_11DB) level_4 = ADC(Pin(34)) level_4.atten(ADC.ATTN_11DB) nom = 'ESP32-ble-uart-gcworks' UUID_UART = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E' UUID_TX = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E' UUID_RX = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E' val_rx = "12" uart = Bleuart(nom, UUID_UART, UUID_TX, UUID_RX) uart.close() def rcp_rx(): global val_rx if uart.any(): while uart.any(): val_rx = uart.read().decode().strip() print('sur rx: ', val_rx) def env_tx(val_tx): uart.write(str(val_tx) + '\n') print("tx", val_tx) send_1=0 send_2=0 send_3=0 send_4=0 while True: #uart.irq(handler=rcp_rx) level_1_value = level_1.read() print("niveau 1",level_1_value) level_2_value = level_2.read() print("niveau 2",level_2_value) level_3_value = level_3.read() print("niveau 3",level_3_value) level_4_value = level_4.read() print("niveau 4",level_4_value) if (level_1.read()==0) and (level_2.read()==0) and (level_3.read()==0) and (level_4.read()==0): env_tx("0") # send water level 0 to smartphone send_1=0 if (level_1.read()!=0) and (level_2.read()==0) and (level_3.read()==0) and (level_4.read()==0) and send_1==0: env_tx("25") # send water level 1 to smartphone send_1=1 send_2=0 if (level_1.read()!=0) and (level_2.read()!=0) and (level_3.read()==0) and (level_4.read()==0) and send_2==0: env_tx("50") # send water level 2 to smartphone send_1=0 send_2=1 send_3=0 if (level_1.read()!=0) and (level_2.read()!=0) and (level_3.read()!=0) and (level_4.read()==0) and send_3==0: env_tx("75") # send water level 3 to smartphone send_2=0 send_3=1 send_4=0 if (level_1.read()!=0) and (level_2.read()!=0) and (level_3.read()!=0) and (level_4.read()!=0) and send_4==0: env_tx("100") # send water level 4 to smartphone send_3=0 send_4=1 time.sleep_ms(500) |
esp_ble_uart.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
from micropython import const import struct import bluetooth # Advertising payloads are repeated packets of the following form: # 1 byte data length (N + 1) # 1 byte type (see constants below) # N bytes type-specific data _ADV_TYPE_FLAGS = const(0x01) _ADV_TYPE_NAME = const(0x09) _ADV_TYPE_UUID16_COMPLETE = const(0x3) _ADV_TYPE_UUID32_COMPLETE = const(0x5) _ADV_TYPE_UUID128_COMPLETE = const(0x7) _ADV_TYPE_UUID16_MORE = const(0x2) _ADV_TYPE_UUID32_MORE = const(0x4) _ADV_TYPE_UUID128_MORE = const(0x6) _ADV_TYPE_APPEARANCE = const(0x19) _IRQ_CENTRAL_CONNECT = const(1 << 0) _IRQ_CENTRAL_DISCONNECT = const(1 << 1) _IRQ_GATTS_WRITE = const(1 << 2) # org.bluetooth.characteristic.gap.appearance.xml _ADV_APPEARANCE_GENERIC_COMPUTER = const(128) # Generate a payload to be passed to gap_advertise(adv_data=...). def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0): payload = bytearray() def _append(adv_type, value): nonlocal payload payload += struct.pack('BB', len(value) + 1, adv_type) + value _append(_ADV_TYPE_FLAGS, struct.pack('B', (0x01 if limited_disc else 0x02) + (0x00 if br_edr else 0x04))) if name: _append(_ADV_TYPE_NAME, name) if services: for uuid in services: b = bytes(uuid) if len(b) == 2: _append(_ADV_TYPE_UUID16_COMPLETE, b) elif len(b) == 4: _append(_ADV_TYPE_UUID32_COMPLETE, b) elif len(b) == 16: _append(_ADV_TYPE_UUID128_COMPLETE, b) # See org.bluetooth.characteristic.gap.appearance.xml _append(_ADV_TYPE_APPEARANCE, struct.pack('<h', appearance)) return payload def decode_field(payload, adv_type): i = 0 result = [] while i + 1 < len(payload): if payload[i + 1] == adv_type: result.append(payload[i + 2:i + payload[i] + 1]) i += 1 + payload[i] return result def decode_name(payload): n = decode_field(payload, _ADV_TYPE_NAME) return str(n[0], 'utf-8') if n else '' def decode_services(payload): services = [] for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE): services.append(bluetooth.UUID(struct.unpack('<h', u)[0])) for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE): services.append(bluetooth.UUID(struct.unpack('<d', u)[0])) for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE): services.append(bluetooth.UUID(u)) return services class Bleuart: def __init__(self, name, UUID_UART, UUID_TX, UUID_RX, rxbuf=100): _UART_UUID = bluetooth.UUID(UUID_UART,) _UART_TX = (bluetooth.UUID(UUID_TX), bluetooth.FLAG_NOTIFY,) _UART_RX = (bluetooth.UUID(UUID_RX), bluetooth.FLAG_WRITE,) _UART_SERVICE = (_UART_UUID, (_UART_TX, _UART_RX,),) self._ble = bluetooth.BLE() self._ble.active(True) self._ble.irq(handler=self._irq) ((self._tx_handle, self._rx_handle,),) = self._ble.gatts_register_services((_UART_SERVICE,)) # Increase the size of the rx buffer and enable append mode. self._ble.gatts_set_buffer(self._rx_handle, rxbuf, True) self._connections = set() self._rx_buffer = bytearray() self._handler = None # Optionally add services=[_UART_UUID], but this is likely to make the payload too large. self._payload = advertising_payload(name=name, appearance=_ADV_APPEARANCE_GENERIC_COMPUTER) self._advertise() def irq(self, handler): self._handler = handler def _irq(self, event, data): # Track connections so we can send notifications. if event == _IRQ_CENTRAL_CONNECT: conn_handle, _, _, = data self._connections.add(conn_handle) elif event == _IRQ_CENTRAL_DISCONNECT: conn_handle, _, _, = data if conn_handle in self._connections: self._connections.remove(conn_handle) # Start advertising again to allow a new connection. self._advertise() elif event == _IRQ_GATTS_WRITE: conn_handle, value_handle, = data if conn_handle in self._connections and value_handle == self._rx_handle: self._rx_buffer += self._ble.gatts_read(self._rx_handle) if self._handler: self._handler() def any(self): return len(self._rx_buffer) def read(self, sz=None): if not sz: sz = len(self._rx_buffer) result = self._rx_buffer[0:sz] self._rx_buffer = self._rx_buffer[sz:] return result def write(self, data): for conn_handle in self._connections: self._ble.gatts_notify(conn_handle, self._tx_handle, data) def close(self): for conn_handle in self._connections: self._ble.gap_disconnect(conn_handle) self._connections.clear() def _advertise(self, interval_us=500000): self._ble.gap_advertise(interval_us, adv_data=self._payload) |
It is possible to connect an ESP32 microcontroller to a smartphone via Bluetooth and use the App Inventor platform to create an app that communicates with the ESP32.
To communicate with the ESP32 from the app, you can use the BluetoothClient component in App Inventor. This component allows you to send and receive data over a Bluetooth connection, and it can be used to control the ESP32 and read data from sensors connected to the ESP32.
We will create a mobile application named ‘esp32_water_level’ with App Inventor which allows to receive the water level in the bottle measured by ESP32 board.
We therefore suggest that you create the design of the application, with the following visual:
To program the application, App Inventor offers us to use the Blocks space which allows you to create a program in the form of a block diagram. Very easy to use but requires some programming logic.
Here is the program of the application made in the Blocks space of the App Inventor: