LOG IN SIGN UP TODAY

Community IoT Garden Using Raspberry Pi and Telegram Bot

April 29th, 2019

IoT garden using Raspberry Pi and Telegram Bot to water plants, flip lights, take NDVI pics, videos, and more…

Things used in this project

Hardware components
Development Board Enclosure, Raspberry Pi 3 Model B×1
Drip irrigation kit×1
Aquarium Pump×1
SparkFun 433Mhz Transmitter Chip×1
Software apps and online services
Telegram

Story

The idea behind IoT garden project

Have you ever played Farmville? – That’s the social network game where you basically manage a simulated farm, you can either do this in a single player or in a multiplayer setting. Now what if that farm was real – then you would say well that would be just real life farming – but bear with me here, what if you could still be online, play as a single player or a multiplayer to manage this real life farm? Then that would be something more than “just farming” right.

Well I don’t have a farm, I live in an apartment in an urban area and have a small garden, but the above idea was my inspiration behind creating an Internet of things (IoT) community garden which could be managed remotely by a group of like-minded people using Telegram app group chat. For those unfamiliar with Telegram, it is a messaging application similar to Whatsapp, but it allows any user to create a bot using an API, a bot is simply some code which responds to commands in an automated fashion. So I implemented my idea by coding up a Telegram Bot which runs on a Rasberry Pi and accepts commands from users – to water plants, take a picture, turn lights on and off. I plan to further expand this in the future by adding temperature and moisture sensors, but for now I simply pull the weather data using weather API for dark sky. On April 4th 2019 I posted about the bot on Facebook groups and soon had random people from around the world join my Telegram group to play with my bot. Currently as I write this article I have about 30-35 people who interact with the bot daily.

Let’s take a small pause – if at this moment you want to test out our community IoT garden yourself, then download the Telegram app on your smart phone and simply look for our chat group called: “iotgarden”,  or click the link :  https://t.me/iotgarden from your mobile device. Another option is to look directly for: ZenofallBot or click the link: https://t.me/Zenofallbot  from your mobile device. 

 What are the differences between the two? 

  • Iotgarden is a Telegram chat group –  there are multiple users in this group, the bot called Zenofallbot is added to the group similar to a real user, more importantly everyone can see each other’s interaction with the bot. The idea here is to build a community where we can not only interact with the bot as a community, but also discuss ideas for improvement to the project, other DIY projects or have general tech discussions. Also you can directly interact with me here and ask questions, I am the admin of this group.
  • Zenofallbot  is the actual Telegram Bot – if you want to privately interact with the bot without being part of the community then directly search its name – no one else will be able to see your interaction.

Once you have initiated a chat with the chat group or directly with the bot, just type the command “/start”, hit send, a menu should pop-up with buttons for actions.

As far as our IoT garden is concerned, management only implies watering the plants at regular intervals, analyzing the plant health –by monitoring photosynthesis activity using Infrared imaging (NDVI), and finally turning led string lights on or off – the last one doesn’t really affect plant health but is purely for garden decoration. It can also be a lot of fun to flip the lights on/off around the garden and take pictures or videos to check if everything worked as designed, this by itself is totally incredible to me – as you could potentially be flipping the lights on/off for my garden from any part of the world. 

As I mentioned before live in an apartment and have a small garden, but if you have a big back yard or have wild animals or rodents roaming around that eat your garden produce – then you could potentially consider expanding the application by introducing a motion detection system to the same setup – and turn on flood lights or some other form of deterrent when motion is detected. The possibilities of what such an integrated IoT system can do are only limited by one’s imagination. The  concept can be further extended to manage an actual farm as long as the Raspberry Pi can be connected to internet – one could use low power Xbee sensors in the farm to monitor environmental activity.

Setup

I built this using simple inexpensive components such as:

  •  Raspberry Pi – the brain that runs the bot
  •  Raspberry Pi NoIR camera with a blue filter
  •  433Mhz radio transmitter chip
  •  433Mhz Christmas light switches – Receivers
  •  Small aquarium pump
  •  Led String Lights

This project requires a power supply and wifi connectivity, this wasn’t a problem for me as I live in an apartment and my garden is 10ft away from my router.

Drip Irrigation

Aquarium Pump

Aquarium Pump

Tubing

Tubing

Connector

Connector

The drip irrigation system mainly consists of a small aquarium pump and tubes, the pump is connected to 433Mhz radio outlet from etekcity, which is in turn connected to a power source. The pump is immersed in a bucket of water. The main reason for choosing the 433Mhz power outlet is that we can use a transmitter chip with Raspberry Pi to turn the outlet On/Off. I have explained how to do this in a previous blog post.

The pump and the tubing I purchased were both from amazon:

Pump : https://www.amazon.com/PonicsPumps-PP21105-Submersible-Hydroponics-Aquaponics

Tubing: https://www.amazon.com/gp/product/B01DEYGBO2/

There are two main things to consider while choosing the pump and pipes:

  •  The power of the pump – for my application I needed a lift of about 6 to 12 inches, as the lift increases the water delivery rate decreases i.e. the gallons per hour specification. The pump I chose delivered 211gph at zero lift, and about 192gph at 12” lift. As my garden is small this was sufficient for me.  I only planned to run the pump for 1min when I watered my plants – this was supposed to deliver approximately 192gph / 60 mins = 3.2gallons of water in 1 min, but empirically I realized it delivered close to 0.5 gallon every 1min I ran the pump. This was still good enough for me.
  • The tubing should fit the pump.<pan>This was the main problem I encountered while setting up the irrigation system was that the smallest connector that came with the pump was ¼’ internal diameter (ID), but the tubing was ¼’ outside diameter (OD). I knew the two were incompatible just based on specification of products before I made the purchase, but I had to make the purchase because I was unable to find drip irrigation pipes in different size or the pump with a smaller nozzle. I solved the problem by buying an elbow connector from home depot, with the right size diameters at both ends

Lights

I have also put up some decorative led string lights around my garden, which are again connected to a 433Mhz power outlet, same as the irrigation pump. As mentioned above the 433Mhz outlet can be turned on/off from a Raspberry Pi using a 433Mhz transmitter chip. The calibration steps for getting the outlet on/off codes is mentioned in a previous blog post.

Camera

I use the Raspberry Pi NoIR camera, with a thin blue filter taped to it, this helps record photosynthesis activity using the Normalized Difference Vegetation Index – NDVI.  I will explain the logic behind NDVI in a later section.  The difference between a regular camera and noIR camera is that NoIR camera does not have an infrared light blocking filter i.e. it captures infrared light.

The details on how to connect the camera to Raspberry Pi are shown in a previous post.

Plant Health Monitoring & Control – Digital Image NDVI, Weather and Watering

Rasberry Pi View

Rasberry Pi View

NDVI Pic

NDVI Pic

As mentioned earlier I use Raspberry Pi NoIR camera with a thin blue filter taped to it, this thin blue filter actually comes in the Raspberry Pi NoIR camera box. More on this can be found here.

A digital image is captured by a camera in terms of pixels and each pixel has <R, G, B> i.e. Red, Green and Blue colors, also called RGB channels. Thus an image in digital form is just an array defined as [height-index, width-index, [r, g, b]], for example let’s say we have an image A.jpg of 1280 x 960 dimension, the first pixel can be found at A[0, 0] and will have some [r, g, b] values: [12, 40, 22] (the range of each of R, G, B is 0-255) and last pixel will be given at A[959, 1279] and will have some other [r, g, b] values and together the whole multi-dimensional array makes an image. i.e. [pixel-row, pixel-col, R, G, B]

The basic principle of NDVI is that during photosynthesis plants absorb visible spectrum of light, but reflect the Infrared wavelengths, so a measure of the reflected infrared light should indicate photosynthesis. Typically the red channel CMOS sensor is also sensitive to infrared wavelengths, and in modern cameras there is a special filter to filter out these infrared wavelengths – although a NoIR camera simply does not have this filter and the red channel indirectly records the infrared wavelengths.

If a physical blue film is taped to the camera it will theoretically capture more Blue light and Infrared light and filter out the visible spectrum R and G wavelengths, allowing for easy calculation of NDVI measure from vectorized image data.

Thus NDVI can then be calculated as: (NIR-Blue)/(NIR+Blue) and the image can be recomposed. 

The physical setup involves connecting the camera to the Pi and then taping the thin blue film filter (that comes in the camera packaging box) on top of it.

The other part of our monitoring system involves keeping an eye on the weather – we use dark sky api and Python libraries to check the weather, dark sky is a weather monitoring service which gives weather data by gps coordinates. One could also get this data by using a temperature humidity sensor directly connected to the Raspberry Pi, but I realized that sensor readings are prone to error, so rather than spending money on the sensor we decided to use an online service.

The photosynthesis monitoring plus the weather data sufficiently captures the monitoring aspect.

Finally we move to the control – which is in terms of making a decision as to whether we water our plants are not based on weather and last time of watering – I have built some restrictions around this, which I will explain in the next section.

Before we go any further, please consider subscribing to our mailing list if you like our article so far and to keep up to date with our news.

Software Functions – Telegram Bot

The software is mainly implemented as a Python script – I have kept it simple and not focused on writing a very good OOP design pattern, as this wasn’t my goal. It is very functional and works. I prefer to use an application called “tmux” on raspberry pi which create a standalone session and allows me to close out of my remote ssh client without stopping the session and killing the Python code after I have kicked off the Python script. To install tmux:

sudo apt-get install tmux  

When you log into raspberry pi remotely, first start tmux and then kickoff the script:

tmux
python3 gardenBot_publish_v1.py &

To detach from session press Cntrl+B and then press D. Now you can close your remote ssh client such as putty. The Python script implements a Telegram bot and communicates as a control client with Telegram server, the commands from users go to the server and the Python code which is running on raspberry pi polls for the commands. In a previous article I have explained in detail how to create your own Telegram Bot. For the script to work you will need some pre-requisites:  Darksky Python library install by typing:

pip3 install darksky

Utility called MP4box used for video conversion.Install by typing:

sudo apt-get install gpac

*gpac is a collection of utilities, mp4box is one of them.

  • Telegram Bot API key
  • Telegram Bot Python library Install by typing:
pip3 install python-telegram-bot

(refer https://python-telegram-bot.org/)

Since I was planning to allow other users to monitor and control my garden, I wanted to make sure that I as admin had full control at all times – i.e. be able to remove users, stop addition of more users, etc. This is actually very easy to do by just using the Telegram user id. Every user that uses the Telegram app for messaging is assigned a unique user-id, you can find your unique user id by simply messaging your bot and reading the message using the web-api.  This user-id is assigned by Telegram to your phone, so cannot be spoofed by software.

How to Find Your User ID?

Open telegram app on your iOS or Android device, search for your newly created bot and send it a message – anything like ‘Hi’Type the following in following command in your web-browser:

https://api.telegram.org/bot<TOKEN>/getUpdates(here the <token> is your token assigned during bot creation, also do not include < >, just copy-paste the key)

The bot on server records this as a simple post request and displays it on browser:

User Functions

Once you have this id, you can use this id and implement your bot such that the bot responds to only this user. In my case I wanted others to be able to use my bot and monitor/control my garden but also be in full control, so I wrote functions accordingly to give me admin privileges.

The main function that I implemented, with which any user begins their interaction with the bot was:

/start

This function responds with basic instructions, adds the new user to IoT control and pops up a command menu, which the user can use to perform actions.

A common user can only use the functions available through this menu, but admin has more functions at their disposal. 

Admin Functions

As Raspberry Pi is resource constrained, watering interval and light flip intervals need to be controlled, this is implemented using some control variables in the code which restrict usage.

Example:

  • Watering can only be done at set intervals – every 4hrs or 6hrs
  • Lights can be flipped every 10mins but not more than that
  • Pics can be taken every 2mins, video can be taken every 5min

Basically the admin can set these controls, this brings us to admin control functions.

There are some special functions which only the admin can use:

/stop: kill the bot gracefully

/fetch: get list of current IoT users

/add: add users

/rm: remove users

/disable {args} : disable menu button functions and autoAdd

/setexp {arg} : set exposure for camera

/setawb {arg}: set white balance for camera

/setLimit {arg}: set time limits for pic, watering, lights, weather, video

Disabling autoAdd gives admin full control on which users can be added manually to manage the garden- after disabling auto add the admin can use /fetch, /add and /rm for user management. 

Also once /stop is executed the bot code will end, and to restart one has to log into raspberry pi and start it.

Further instructions are provided in the Python code.

The code

Finally what you all have been waiting for, my actual Community IoT Garden bot code. There are three files for this:

1. gardenBot_publish_v1.py : This is telegram bot wrapper and main file to run

2. iotcontrol.py : This is where the actual user functions are implemented

3. NDVI.py : This is for NDVI pics

You can download all three from my website in a zip, after registration.

Disclaimer: The Python source code below is provided by Zen Of All LLC for free upon registration, the users (downloaders) of the code are free to modify it as they see fit. Zen Of All LLC assumes no legal responsibility or liability towards the code, its maintenance, usage or any modifications by the users (downloaders).

In English: I wrote this code very fast for testing my proof of concept idea – feel free to read it carefully and edit as per your own needs, I am not responsible if something breaks. 

You will need to create a login for this website to download the code.   

Please contact: contact@zenofall.com for any questions.

Hope you enjoyed the article and followed along, thanks for reading,  don’t forget to subscribe to our mailing list for updates.

Schematics

System Schematic

System diag uyqfboe9di

Code

IoTGarden Code

PythonPython Code – Run file , keep all three files in same folder and run:
python3 gardenBot_publish_v1.py &

# -*- coding: utf-8 -*-
"""
Created on Sat Apr  7 13:26:28 2018

@author: Zen Of All LLC (zenofall.com)
"""


import threading
import os



from iotcontrol import iotcontrol
from telegram import InlineKeyboardButton, InlineKeyboardMarkup

from telegram.ext import Updater
from telegram.ext import CommandHandler , CallbackQueryHandler
from telegram.ext import MessageHandler, Filters
import logging
##############################################################################################
darkskyKey = '<Enter dark sky token>'
updater = Updater(token='<TELEGRAM TOKEN>') #Insert bot token
#required by bot to execute functions see example: https://python-telegram-bot.org/
control = iotcontrol(1234567,darkskyKey,33.8463634,-84.373057) 
# 1234567 is example admin id : find yours by going to web-api of telegram: https://api.telegram.org/bot<TOKEN>/getUpdates
#<TOKEN> is telegram token during bot creation
#read: https://zenofall.com/raspberry-pi-telegram-home-automation/
#replace: 33.8463634,-84.373057 by latitude longitude of your location from google maps
#we use adminId for special privileges on the bot

dispatcher = updater.dispatcher 
#bot examples: https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples

#logging is always good

#define logging format and file location



####################Bot User Functions ##############################

def start(bot,update): #display menu
    """ BotFunction: First function using which users are supposed to interact with this bot"""
   

    
    control.autoAdd(bot,update)
    
    
    keyboard = [[InlineKeyboardButton("Instructions", callback_data='5')], 
                 [InlineKeyboardButton("Take Pic", callback_data='1')],
                 [InlineKeyboardButton("NDVI Pic", callback_data='8')],
                 [InlineKeyboardButton("Video", callback_data='9')],
                 [InlineKeyboardButton("Local Weather", callback_data='7')],
                 [InlineKeyboardButton("Water Plants", callback_data='2')],
                [InlineKeyboardButton("Ligts on/off", callback_data='3')],
                [InlineKeyboardButton("Status", callback_data='4')],
                [InlineKeyboardButton("Tutorial & Code", callback_data='6')]
                ]
    
    message="Hello {} (telegram_id:{}).\nPlease read: Instructions first.\nType& send:/start again to pull up menu at any time.\n*Disclaimer: Bot logs all user commands. \nPlease Choose: \n".format(update.message.from_user.first_name,update.message.from_user.id)
    reply_markup = InlineKeyboardMarkup(keyboard)

    bot.send_message(chat_id=update.message.chat_id,text=message, reply_markup=reply_markup)
            

def button(bot,update):
    """ BotFunction: Function that implements the button callbacks"""
    query = update.callback_query
    bot.answer_callback_query(callback_query_id=query.id, text="Choice registered,processing request..")
    
        
    if(query.data=='1'):
         
        
        #control.sendPic(bot,update,False)
        t=threading.Thread(target=control.sendPic,args=(bot,update,False))
        t.setDaemon(True)
        t.start()

    if(query.data=='8'):
        #global enablePic
        
        t=threading.Thread(target=control.sendPic,args=(bot,update,True))
        t.setDaemon(True)
        t.start()

    if(query.data=='9'):
        #global enablePic
      
        t=threading.Thread(target=control.recordVideo,args=(bot,update))
        t.setDaemon(True)
        t.start()

    if(query.data=='2'):
        
        control.water(bot,update)
    
    if(query.data=='3'):
        
        control.light(bot,update)
         
    if(query.data=='7'):
        
        control.weather(bot,update)

    if(query.data=='4'):
    
     control.status(bot,update)

    if(query.data=='5'):
        control.instructions(bot,update)

    
    if(query.data=='6'):
        control.tutorial(bot,update)

############# Admin only program functions####################
            

def unknown(bot, update):
    """ Unkwown command handler"""
    logging.info('/unknown,{},{}'.format(update.message.from_user.first_name,update.message.from_user.id))
    bot.send_message(chat_id=update.message.chat_id, text="Sorry Command Not Recognized! Type: /start for all user actions.")            

def shutdown():
    
    updater.stop()
    updater.is_idle=False

def stop(bot, update): #hardcoded for security only i can issue this command
    """ 
    Admin Command: stop the bot
    Usage:
        /stop
        
    """
    #global adminId
    logging.info('/stop,{},{}'.format(update.message.from_user.first_name,update.message.from_user.id))
    if(update.message.from_user.id==control.getAdminId()):
        bot.send_message(chat_id=update.message.chat_id, text="Stopping Server!")    
        threading.Thread(target=shutdown).start()
    else:
        bot.send_message(chat_id=update.message.chat_id, text="ERROR: Unauthorized User!")

def addIoTUser(bot,update,args):
    """ 
    Admin Command: add users manually
    Usage:
        /add 12345 324567 8726251
        
        The numbers are ids of users
        
    """
    control.addIoTUser(bot,update,args)

        
        
def removeIoTUser(bot,update,args):
    """ 
    Admin Command: remove users manually
    Usage:
        /rm all
        /rm 123445
    """
    control.removeIoTUser(bot,update,args)

        

def fetchIoTUserList(bot,update):
    
    """ 
    Admin Command: add users manually
    Usage:
        /fetch
        
    """
    control.fetchIoTUserList(bot,update)

                    

def disable(bot,update,args):
    
    """ 
    Admin Command: disable functions in button menu
    Usage:
        /disable 1  (for pic)
        /disable 2  (for water)
        /disable 3  (for light)
        /disable 4  (for video)
        /disable all (disable all)
        
    """
    control.disable(bot,update,args)

    

def setAwb(bot,update, args):
    
    """
    Admin function: set white balance
    Usage:
        /set 1.0 1.3 (red,blue)
    
    """
    control.setAwb(bot,update,args)

            
def setExp(bot,update, args):
    
    """
    Admin function: set white balance
    Usage:
        /setExp auto [auto, sports, night]
    https://picamera.readthedocs.io/en/release-1.10/api_camera.html?highlight=exposure_mode#picamera.camera.PiCamera.exposure_mode
    """
    control.setExp(bot,update,args)


def setLimit(bot,update,args):
    
    """
    Admin function: set time limits
    Usage:
        /setLimit pic 2.0
        /setLimit water 5.0
         
    """
    control.setLimit(bot,update,args)
   
                     
        
#def clear(bot,update,chat_data):
#    chat_data.clear()

    
       
    
####____global variables____#########
 


#Kill ServoBlaster - interferes with GPIO #something specific to me
###comment this out if you dont have servo blaster
try:
    os.system("sudo killall servod")      
except Exception as e:
    print(e)
    pass
############ #comment ends
    
#####____HANDLERS_____#######
#bot examples: https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples
start_handler = CommandHandler('start', start)
stop_handler = CommandHandler('stop', stop)
#menu_handler = CommandHandler('menu', menu)
addHandler = CommandHandler('add',addIoTUser, pass_args=True)
removeHandler = CommandHandler('rm',removeIoTUser,pass_args=True)
fetchHandler = CommandHandler('fetch',fetchIoTUserList)
disable_Handler = CommandHandler('disable',disable,pass_args=True)
awbHandler = CommandHandler('setawb',setAwb,pass_args=True)
expModeHandler = CommandHandler('setexp',setExp,pass_args=True)
setLimitHandler = CommandHandler('setLimit',setLimit,pass_args=True)
#clearHandler = CommandHandler('clear',clear,pass_chat_data=True)
unknown_handler= MessageHandler(Filters.command, unknown)

#####____DISPATCHERS_____#######
dispatcher.add_handler(start_handler)
dispatcher.add_handler(stop_handler)
#dispatcher.add_handler(menu_handler)
dispatcher.add_handler(addHandler)
dispatcher.add_handler(removeHandler)
dispatcher.add_handler(fetchHandler)
dispatcher.add_handler(disable_Handler)
dispatcher.add_handler(awbHandler)
dispatcher.add_handler(expModeHandler)
dispatcher.add_handler(setLimitHandler)
dispatcher.add_handler(CallbackQueryHandler(button))

#dispatcher.add_handler(clearHandler)
dispatcher.add_handler(unknown_handler) #Always keep unkown handler last else commands not recognized
#start the bot client - poll for server messages
updater.start_polling()
updater.idle()

This article was originally posted by zenofall on hackster.io

WP2FB Auto Publish Powered By : XYZScripts.com