Posted on Leave a comment

Wireless Plant Watering System using Raspberry Pi Pico W

Every morning my mom waters the plant. She has to water them every day and sometimes in summer, she must provide water twice a day.

In winter plant needs water when necessary.

Solution:

For the above problem, I developed this project using raspberry pi pico w.

Here is what it does:

  1. It connects to the WiFi router. The wifi router allocates a fixed IP address. For that, I created a new entry in the DHCP bindings of the router.
  2. When you visit the IP address 192.168.1.101
  3. It samples the soil moisture sensor through the ADC. And display an HTML page that shows the status of ADC and the onboard LED.
  4. The HTML page also has a button for turning on the pump.
    I have kept it manual.
  5. When the PUMP ON button is pressed the water pump is turned ON. The water pump is connected via the L298n module. Which is controlled by a PWM signal of 1Khz frequency. The duty cycle is slowly increased to 75%.
    There is a timeout of 10 Seconds. If the timeout is reached the water pump will be turned off.

Schematic Diagram

Schematic Diagram

Micropython Code

import network
import socket
import time
from time import sleep
from picozero import pico_temp_sensor, pico_led
import machine

ssid = 'Abhay'
password = 'AK26@#36'
'''
# Pin GP9 (physical pin 5) on PicoZero
GPIO_PIN = 9

# Set up the GPIO pin as an output
pin9 = machine.Pin(GPIO_PIN, machine.Pin.OUT)

# Turn off the GPIO pin
pin9.off()
'''
GPIO_PIN_9 = machine.Pin(9)
pwm9 = machine.PWM(GPIO_PIN_9)

    
def ADC():
    adc = machine.ADC(0)  # Initialize ADC on pin A0
    sensor_value = adc.read_u16()  # Read the analog value from the sensor
    # Add your code to process and display the sensor value as per your requirements
    #print(sensor_value)
    #time.sleep_ms(500)  # Delay between readings (adjust as needed)
    #sensor_value = 18756
    percentage = 100 - ((sensor_value / 65535) * 100)
    #print(f"sensor_value: {sensor_value} percentage: {percentage}")
    return sensor_value,percentage
    
    
def gen_pwm(duration, timeout):
    # Set PWM frequency
    pwm9.freq(1000)  # Set frequency to 1 kHz

    start_time = time.ticks_ms()  # Get the initial timestamp
    pump_started = False

    while time.ticks_diff(time.ticks_ms(), start_time) < timeout:
        # Check water level using ADC
        ADC_Read = ADC()
        water_level = ADC_Read[1]
        #adc.read()

        if not pump_started and water_level < 50:
            # Start the pump by gradually increasing the duty cycle
            for duty in range(0, 32767, 100):
                pwm9.duty_u16(duty)
                time.sleep_ms(duration)  # Adjust the delay as needed for smooth transition
                ADC_Read = ADC()
                water_level = ADC_Read[1]
                
                if water_level >=50 :
                    break
            pump_started = True

        if water_level >= 50 or pump_started and water_level <= 0:
            # Stop the pump by setting the duty cycle to 0
            pwm9.duty_u16(0)
            break

    # Stop the PWM signal
    pwm9.duty_u16(0)

def connect():
    #Connect to WLAN
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(ssid, password)
    while wlan.isconnected() == False:
        print('Waiting for connection...')
        sleep(1)
    ip = wlan.ifconfig()[0]
    print(f'Connected on {ip}')
    return ip

def open_socket(ip):
    # Open a socket
    address = (ip, 80)
    connection = socket.socket()
    connection.bind(address)
    connection.listen(1)
    return connection

def webpage(temperature, state,user_value):
    #Template HTML
    ADC_Value = ADC()
    html = f"""
            <!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <form action="./lighton" style="display: flex; justify-content: center;">
        <input type="submit" value="Light on" style="font-size: 40px;" />
    </form>
    <form action="./lightoff" style="display: flex; justify-content: center;">
        <input type="submit" value="Light off" style="font-size: 40px;" />
    </form>
    <p style="font-size: 20px;">LED is {state}</p>
    <p style="font-size: 20px;">Temperature is {temperature}</p>
    <p style="font-size: 20px;">ADC Value is {ADC_Value[0]}</p>
    <p style="font-size: 20px;">ADC % is {ADC_Value[1]}</p>
    
    <form action="./pumpon" style="display: flex; justify-content: center;">
        <input type="submit" value="Pump on" style="font-size: 40px;" />
    </form>
    <form action="./pumpoff" style="display: flex; justify-content: center;">
        <input type="submit" value="Pump off" style="font-size: 40px;" />
    </form>
    
    <h1>Numeric Form</h1>
    <form method=POST action="/usrval">
        <label for="value">Enter a numeric value:</label><br>
        <input type="number" id="value" name="value" required><br><br>
        <input type="submit" value="Submit">
    </form>
    <p>User value: {user_value}</p>  <!-- Display the user-submitted value -->
</body>
</html>


            """
    return str(html)
def serve(connection):
    #Start a web server
    state = 'OFF'
    pico_led.off()
    temperature = 0
    user_value = None  # Variable to store the user-submitted value
    while True:
        client = connection.accept()[0]
        request = client.recv(1024)
        request = str(request)
        rqst1 = request.split()
        '''
        for x1 in rqst1:
            if(x1.find("usrval") != -1):
                print(rqst1)
                #print(x1)
        #print(rqstfind)
        '''
        try:
            
            for x1 in rqst1:
                if "value=" in x1:
                    user_value = x1.split("=")[2].strip("'")
                    print(user_value)
        except:
            pass
        
        try:
            request = request.split()[1]
        except IndexError:
            pass
        if request == '/lighton?':
            pico_led.on()
            state = 'ON'
        elif request =='/lightoff?':
            pico_led.off()
            state = 'OFF'
        elif request =='/pumpon?':
            #pin9.on()
            gen_pwm(10,10000)
            print("\n\n"+request)
            #state = 'OFF'
        elif request =='/pumpoff?':
            #pin9.off()
            print("Pump OFF")
        elif request == '/usrval':
          #  print("\n\n"+request)
            index = request.find('value=')
            
            if index != -1:
                end_index = request.find(' ', index)
                if end_index == -1:
                    end_index = len(request)
                user_value = request[index + len('value='):end_index]
                print(f"\n\nValue: \t {user_value}\n\n")
        temperature = pico_temp_sensor.temp
        html = webpage(temperature, state,user_value)
        client.send(html)
        client.close()

try:
    ip = connect()
    connection = open_socket(ip)
    serve(connection)
except KeyboardInterrupt:
    machine.reset()
Posted on Leave a comment

How to make a plant watering system using Arduino Uno

Sometimes we are so busy in our work or in our day-to-day life that we forget to water our plants on time. Or in the summertime when the plants need additional water to sustain themselves in the high-temperature region like New Delhi.

This is a simple project that one can assemble and implement within a few minutes.

To make this project you will need some modules which are readily available in the market.

Arduino UNO x 1

Moisture Sensor x 1

A 5V relay x 1

5V water pump x 1

A short length of plastic or rubber tube x 1 – 1.5m

Rechargeable Power Bank x 1

#define sense A0
#define relay 9
void setup() {
  // put your setup code here, to run once:
pinMode(sense, INPUT);
pinMode(relay, OUTPUT);

Serial.begin(9600);
}
int val;
void loop() {
  // put your main code here, to run repeatedly:
val = analogRead(sense);
Serial.println(val);

if (val < 600)        /*  adjust this value to control how much soil must be moist */
{
  digitalWrite(relay, HIGH);
}
else
{
  digitalWrite(relay, LOW);
}
delay(400);
}
Posted on Leave a comment

How to use internal temperature sensor of ATmega328pb

ATmega328PB is a new semiconductor microcontroller from Microchip semiconductors. I have used its previous generation which is ATmega328 and ATmega328P. They were usually found on Arduino Uno and Arduino nano.

This new IC has a temperature sensor built into it. Which is handy for measuring the die temperature. Which can make device stable in high-temperature design. It is not accurate as a dedicated temperature sensor. But it gives you a rough idea. Using this you can the processes.

It is not an Ambient temperature Sensor.

/*
 * main.c
 *
 * Created: 8/15/2022 4:06:41 PM
 *  Author: abhay
 */ 
#define F_CPU 16*1000000
#include <xc.h>
#include "uart.h"
#include "util/delay.h"
#include <stdlib.h>
long Ctemp;
unsigned int Ftemp;

int main(void)
{
		DDRD &= ~(1 << DDD0);							// PD0 - Rx Input
		DDRD |= (1 << DDD1);							// PD1 - Tx Ouput
		USART_Init();
		
	/* Replace with your application code */
	ADMUX = (1<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);
	ADCSRA =  (1<<ADPS2) |(1<<ADPS1) | (1<<ADEN);
	
	ADCSRA |= (1<<ADSC);
	
	while ((ADCSRA & (1<<ADSC)) !=0);
	
	while (1)
	{
		ADCSRA |= (1<<ADSC);
		while ((ADCSRA & (1<<ADSC)) !=0);
		
		Ctemp = ((ADC - 247)/1.22)*1000;
		Ftemp = (Ctemp * 1.8) + 32;
		
		USART_Transmit( (((int)Ctemp/100000)%10) + 48);
		USART_Transmit( (((int)Ctemp/10000)%10) + 48);
		USART_Transmit( (((int)Ctemp/1000)%10) + 48);
		USART_Transmit('.');
		USART_Transmit( (((int)Ctemp/100)%10) + 48);
		USART_Transmit( (((int)Ctemp/10)%10) + 48);
		USART_Transmit( ((int)Ctemp%10) + 48);
		
		USART_Transmit('\n');
		_delay_ms(1000);
	}
	return -1;
}
Posted on Leave a comment

Battery Monitoring with Led Light Control Using ESP32 Bluetooth for my Solar System

I need to monitor battery voltage to check weather my charging system is working correctly or not. But to do that i have get up and walk with my multimeter towards the battery and i have to take these reading in night.

I placed my battery in a corner where there is very little light. So I added a transistor switch which can be controlled using Bluetooth to turn on the led light. Which provides enough light to act as a night light.

The ESP32 also has an ADC built into it. Which is very poor in terms of accuracy. It gets you the idea that there is something to work with but it does not give very precise reading like a multimeter.

Also, the ESP32 ADC is non-linear. The ADC also has an attenuation feature. Which by default is set to 11db. which gives us a workable range of up to 3.3V. But there are flat-out regions which need to be taken into account if you want to measure anything from this ADC. There is a 0 – 0.2V region in which the value read is constant, and there is a 2.9V to 3.3V region which also gives you constant reading values.

Resolution is 12-bit by default.

To measure a large voltage using this device. I made a voltage divider.

Battery +ve———/\/\/ R1 \/\/\/ ———— Vout —————— /\/\/\/\/ R2 \/\/\/\/ ———-GND

R1 = 10 kilo Ohm

R2 = 1 kilo Ohm

Which gives me a dividing factor of 11.

So if 11 V is available at the battery anode. Then the V out is 1V.

Normally the lead acid battery voltage goes from 10V(fully discharged) to 14.6V(Maximum charge) to 15V(Over Charged)

The ADC values are converted to battery voltage using the following equation

( (analogValue * (3.3/4096 ) ) * ((9820+985)/985) ) + 3.3

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;


char var1;
int analogValue;
uint8_t i;
int avg_adc;

void setup()
{
  Serial.begin(115200);
  SerialBT.begin("ESP32test"); //Bluetooth device name
  Serial.println("pair it with bluetooth!");
pinMode(2, OUTPUT);
 
}

void loop()
{
  /*
   * UART 
   */
  if (Serial.available()) {
  
    SerialBT.write(Serial.read());
  }


/*
 * Bluetooth serial
 */
  if (SerialBT.available()) {
      var1 = SerialBT.read();
    Serial.write(var1);
  }
    if (var1 == '9')
{
  digitalWrite(2,HIGH);
}
else if(var1 == '1')
{
  digitalWrite(2,LOW);
}


avg_adc = 0;
for(i =0 ; i< 100; i++)
{
  avg_adc += analogRead(34);
}
analogValue = avg_adc / 100;

SerialBT.printf("ADC = %d\n",analogValue);
  SerialBT.printf("volt = %f\n",   ( (analogValue * (3.3/4096 ) ) * ((9820+985)/985) ) + 3.3 ) ;
    delay(1000);
}

Since the ADC is not accurate it goes all over the place. To dampen its effect on the reading I am averaging 100 readings of ADC.

avg_adc = 0;
for(i =0 ; i< 100; i++)
{
  avg_adc += analogRead(34);
}
analogValue = avg_adc / 100;

TIP3055 BJT is used as a low-side switch. R1 gives a base current of 330uA(=3.3/10000) which gets multiplied by the beta or hFE 70 of transistor to get a collector current of 0.023A or 23mA.

Posted on Leave a comment

How to interface potentiometer to ESP32 to read ADC Values

Here is the simple code to read the ADC value and show it in the serial monitor of Arduino ide.

const int Analog_channel_pin= 34;
int ADC_VALUE = 0;
float voltage_value = 0; 
void setup() 
{
Serial.begin(115200);
}
void loop() 
{
ADC_VALUE = analogRead(Analog_channel_pin);
Serial.print("ADC VALUE = ");
Serial.println(ADC_VALUE);
delay(1000);
voltage_value = (ADC_VALUE * 3.3 ) / (4095);
Serial.print("    Voltage = ");
Serial.print(voltage_value);
Serial.println("volts");
delay(1000);
}
The output of serial monitor