How To Monitor Your Houseplants With Raspberry Pi Pico W and Telegram

Pico W Telegram Bot
(Image credit: Tom's Hardware)

House plants need attention and when you’re sitting at your desk working away, sometimes you forget to look after them. Our patient is “Gary” a Gasteria succulent from Ikea who needs very little care, and that means I forget to water him. So how can the Raspberry Pi Pico W help me to take better care of Gary?

Soil moisture sensors measure the conductivity of the soil and send the value to the Raspberry Pi Pico W (or other microcontroller) as a voltage. This voltage is read by an analog GPIO pin and converted to a value between 0 and 65535. The lower the number, the drier the soil. This can then be used as a trigger to send a message.

In this how-to, we’ll learn how to take a series of  sensor readings, work out their median value and use that to determine if Gary needs a drink. Gary will then send a message to us via a Telegram Bot.

For This Project You Will Need

Building the Circuit

(Image credit: Tom's Hardware)

The circuit is extremely simple. We have a soil moisture sensor connected to three pins of the GPIO. The first two pins, 3V3 power and GND provide the sensor with the power that it needs. 

The third pin, Signal, is an output pin which sends a value to the Raspberry Pi Pico. The output is a voltage which the corresponding GPIO reads as a value between 0 and 65535. This value is then used in the code to determine if the plant is thirsty.

The soil moisture sensor connects as follows.

Swipe to scroll horizontally
ColorSoil Moisture SensorRaspberry Pi Pico
Red+ / VCC3V3 (Physical pin 36)
YellowS / SignalGP26
Black- / GNDAny Ground / GND pin

Setting Up A Telegram Bot

Telegram is an easy-to-use instant messaging service which has a refreshingly simple means in which we can communicate from a Raspberry Pi Pico W. Using a Bot, we can create a channel devoted to our house plants or even home security.

Creating a Telegram Bot is a simple process, and luckily we have The BotFather on hand to help us.

1. Sign in to your Telegram account. We used the Windows client for an easier workflow.

2. Create a chat with BotFather. BotFather is a bot used to create and manage bots.

3. Create a new bot using the /newbot command and press Enter. BotFather will create a wizard to guide you through the bot creation process.

/newbot

4. Make a note of the API key, it is necessary for the project. Without this we cannot communicate with the bot using our code.

5. In Telegram, create a new chat with IDBot, ask for your ID. Make a note of the ID.

/getid

Writing the Code 

All of the project code is written in MicroPython, using the very latest MicroPython release for the Raspberry Pi Pico W. We use Thonny to write and test the code directly on the Raspberry Pi Pico W. 

1. Follow these steps to download the latest version of MicroPython for the Raspberry Pi Pico W. The most important steps are to download and install the UF2 firmware image and to set up Thonny. The rest are optional.

2. Open Thonny and click on the Stop button to refresh the connection. This ensures that the Python Shell is open and working correctly.

3. Create a new file and paste the contents of this link. Save the file as statistics.py to the root of the Raspberry Pi Pico W. This file is a module that contains all of the statistical functions necessary to select the median value from a list of data. The project was created by Roberto Colistete Junior.

4. Create a new file and in there create four objects, SSID, PASSWORD, API, and ID.

5. For the SSID object, assign it the name of your Wi-Fi access point / router.

SSID = “YOUR WI-FI AP NAME HERE”

6. For the password, assign the Wi-Fi password.

PASSWORD = “YOUR SECRET PASSWORD”

7. For the API, assign the Telegram Bot API key. Ensure that the key is inside the “ “.

API = "YOUR TELEGRAM BOT API KEY"

8. For the ID, assign your Telegram user ID. Ensure that the ID is inside the “ “ as this will set the value as a string.

ID = “YOUR USER ID HERE”

9. Save the file to the Raspberry Pi Pico W as secrets.py.

SSID = “YOUR WI-FI SSID”
PASSWORD “YOUR WI-FI PASSWORD”
API = “YOUR TELEGRAM BOT API KEY”
ID = “YOUR TELEGRAM USER ID”

10. Create a new file and import a series of Python modules.

     a. Machine contains functions and classes necessary to use the GPIO (Pin) and analog inputs (ADC).

     b. Time is used to add a delay to the code.

     c. Network makes Wi-Fi connections.

     d. Urequests (micro requests) is a MicroPython version of requests which are used to send and receive data over a network.

     e. Statistics, a module containing functions to perform statistical analysis of data.

     f. Secrets, a module that contains all of our Wi-Fi details and API keys.

from machine import Pin, ADC
import time
import network
import urequests
import statistics
import secrets

11. Create an object, sensor, and create a connection to the soil moisture sensor at GPIO 26. This object will set the sensor input as analog, using a value between 0 and 65535 to represent the conductivity of the soil. The higher the number, the better the conductivity.

sensor = ADC(Pin(26))

12. Create an object, wlan, and use it to make a connection to your Wi-FI access point. The connection is made active, then using the SSID and PASSWORD stored in secrets.py we connect to the access point. A five second pause lets the connection become stable, then we print the current status of the connection. If connected we see TRUE, if it fails, we see FALSE.

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(secrets.SSID, secrets.PASSWORD)
time.sleep(5)
print(wlan.isconnected())

13. Create an empty list called “readings”. A list is also known as an array and we use it to store multiple values in an easily readable format.

readings = []

14. Create the first part of a try, except statement, and set the code to run a while True loop. Try, except is an error handling statement. The code will try to run what is contained within it, but if there is an exception or error, it will default to a section of code that will deal with it.

try:
   while True:

15. Using a for loop, collect five readings from the soil moisture sensor and append each reading to the readings list in one second intervals. This section of code will read the GPIO pin connected to the sensor and then take the value and store it in the list. Printing the readings is useful for debugging any issues.

       for i in range(5):
           reading = sensor.read_u16()
           readings.append(reading)
           print(readings) 
           time.sleep(1)

16. Outside of the for loop, create an object, median_value and in there store the median (midpoint) value from the collection of readings.

       median_value = statistics.median(readings)

17. Use a conditional statement to check the median_value against a hard coded value. In our tests we chose 400 as the point in which our gasteria plant would require water. Tweak this value to meet the needs of your plant.

       if median_value < 400:

18. If the plant requires water, using urequests send a message to Telegram then print a message to the Python shell. Note that we use secrets.API to insert our API key, and secrets.ID to send our user ID. The actual message is here sendMessage?text=Gary is thirsty.

    urequests.get("https://api.telegram.org/bot"+secrets.API+"/sendMessage?text=Gary is thirsty&chat_id="+secrets.ID)
         print("Message Sent")

19. Using else, the plant determines that it has enough water and does not need any at this time. This then triggers a one hour delay to the code.

       else:
           print("Gary has enough water")
       time.sleep(3600)

20. Create an exception handler, designed to handle an OS Error (no Wi-Fi connection) that prints a message to the Python shell. The print(“@”*68) lines create decorative borders above and below the message.

except OSError:
   print("@"*68)
   print("@ Cannot connect to the Wi-Fi, please check your SSID and PASSWORD @")
   print("@"*68)

21. Save the code as main.py on the Raspberry Pi Pico W. This will force the Pico W to load the code each time it is power cycled.

22. Power cycle the Pico W and wait for your house plants to demand their water!

Complete Code Listing

from machine import Pin, ADC
import time
import network
import urequests
import statistics
import secrets
sensor = ADC(Pin(26))
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(secrets.SSID, secrets.PASSWORD)
time.sleep(5)
print(wlan.isconnected())
readings = []
try:
   while True:
       for i in range(5):
           reading = sensor.read_u16()
           readings.append(reading)
           print(readings) 
           time.sleep(1)
       median_value = statistics.median(readings)
       if median_value < 400:
           urequests.get("https://api.telegram.org/bot"+secrets.API+"/sendMessage?text=Gary is thirsty&chat_id="+secrets.ID)
           print("Message Sent")
       else:
           print("Gary has enough water")
       time.sleep(3600)
except OSError:
   print("@"*68)
   print("@ Cannot connect to the Wi-Fi, please check your SSID and PASSWORD @")
print("@"*68)
Les Pounder

Les Pounder is an associate editor at Tom's Hardware. He is a creative technologist and for seven years has created projects to educate and inspire minds both young and old. He has worked with the Raspberry Pi Foundation to write and deliver their teacher training program "Picademy".