As we know sunlight is food for plants. Plants use sunlight to produce energy which fuels the production of organic compounds known as glucose, which a plant can use as food. But are we sure whether plants are getting the right amount of sunlight or are being shadowed? We can find out the same by using plant light monitoring system.
The Plant monitoring system used in this project has mainly three functionalities. One, to sense the amount of sunlight falling on the Light Detecting Resistor ( LDR). LED turns on when sunlight required is below threshold. Two, to send an alert on the amount of sunlight falling on the photoresistor and buzz when there is an anomaly detected.
This project also helps in data visualization where we will be able to collect the values indicating intensity and plot them over a line graph. An alert system has been set up using Telegram Bot to notify the operator when there is an anomaly detected.
1.1 Overview and alert notificationLDR connections :
- Connect one end of LDR to A0 pin through 330ohm resistor and the other end to 3.3 V pin.
- Connect the other end of the resistor to GND pin.
Buzzer connections :
- Connect positive end of Buzzer to pin 0 (digital GPIO) and negative end of Buzzer to GND pin.
LED connections :
Connect positive end of LED to pin 1 through 330 ohm resistor and negative end of LED to GND pin.
Circuit connections are shown stepwise. Take a look at these images below for a clear understanding.
This section guides us is in setting up our Bolt wifi module, configuring hardware and visualization of light intensity data.
3.1.1 Bolt device configuration1. Login to your Bolt app. Follow the instructions and link your Bolt device to the Bolt cloud.
Once this is done plug in the USB cable to your Bolt wifi module. The other end of the cable is connected to a power source like power bank. Ensure that both the LEDs, blue and green are stable.
Blue LED indicates connection of your Bolt device (Bolt wifi module) to the wifi network and green LED indicates whether your device is connected to the Bolt cloud.
2. Login into cloud.boltiot.com . Select the 'Products' tab. Create a new product for our light monitoring system by clicking on ‘+Add Product’.
3. Enter the product name, type of device and type of data collection and click done.
4. To configure the product click on the Configure Product icon.
5. Select a pin for your circuit and call the pin by a variable name. This will create a variable which will store the received sensor value. As LDR is an analog sensor I have chosen A0 pin.
6. Save your hardware configuration and move on to the code section.
In the Code section enter a file name for your code. Choose the extension as.js and import the following code. This code is used to plot line graph. The code tells the Bolt Cloud how to plot the light intensity data for visual representation.
setChartLibrary('google-chart');
setChartTitle('Bolt Plant Data Visualization');
setChartType('lineGraph');
setAxisName('Time','Light data');
plotChart('time_stamp','light');
Code description:
- setChartLibrary function sets the data visualisation library. The most commonly used library in Bolt Cloud among others is Google Library.
- setChartTitle function allows us to choose the title of the graph.
- setChartType function is used to choose the type of chart. In this project Line graph is used.
- setAxisName is used to set names for the X Axis and Y Axis.
- plotChart allows us the choose a variable in the chart.
7. Once you have imported your code click on the’ Save your configuration’ icon.
8. Click on the Link icon to link your nearly created product with the Bolt wifi module.
9. Deploy the code by clicking on Deploy configuration icon. This function transfers the data to Bolt cloud.
3.1.2 Bolt device ID and API key
- Bolt device ID can be obtained on clicking the devices column.
.
- Bolt device API key can be obtained by clicking on the API column.
Click on ‘View this device’ icon on your Bolt dashboard to observe the plot of Light data versus time.
- Download Telegram app. You can find it in play store and app store. Open the application and swipe from the left side. In the menu click on ‘New Channel’.
- Enter Name and Description for your channel. You can also add a profile photo.
- Set the channel as Public. Enter a permanent link for your channel. You can use numbers (0 to 9) and lowercase letters to create the channel link.
- Choose a name for your channel link. You can use something like plant_monitor_bot followed by your email ID. Example, if my email ID is xxx@gmail.com the channel link name is plant_monitor_bot_xxx_gmail_com. This is just for reference. You are free to use any name of your choice.
You have now created your Telegram channel. Let’s move on.
3.3.2 Create a new Bot- Click on the search icon on the top right corner and type in "botfather". Select BotFather channel with a blue tick.
- Type “/start” in the window to get started. Enter "/newbot" to create a new Bot. Enter Bot name and Bot username.
- Bot token is provided after executing the above commands. Keep this token secure. This token is used to control the Bot as well as send messages.
The telegram_bot_id will be used in the python code to send messages. Add it to the channel created previously to send alerts.
- Next step is to add the newly created Bot to your channel. Click on the channel name ( top of your channel’s page) to open channel’s information.
- Under ‘Members’ tab click on administrators.
- Search your newly created Bot. You will now see the newly created Bot in the list of administrators for the channel. Choose your Bot and make sure you enable the Bot to post messages. Click on the tick mark at the top right corner to continue.
The basic structure of an LDR is shown below.
A Light Dependent Resistor (LDR) also called photoresistor or a cadmium sulfide (CdS) cell is basically a photocell that works on the principle of photoconductivity.
The structure of a light-dependent resistor consists of a light-sensitive material which is deposited on an insulating substrate such as ceramic. The material, usually cadmium sulphide (CaS) is deposited in a zigzag pattern in order to obtain the desired resistance and power rating.
LDR works based on the principle of photoconductivity. Photoconductivity is an optical phenomenon in which the material’s conductivity is increased when light is absorbed by the material.
When light falls i.e. when the photons fall on the device, the electrons in the valence band of the semiconductor material are excited to the conduction band. These photons in the incident light should have energy greater than the band gap of the semiconductor material to make the electrons jump from the valence band to the conduction band. Hence when light having enough energy strikes on the device, more and more electrons are excited to the conduction band which results in a large number of charge carriers. The result of this process is more and more current starts flowing through the device when the circuit is closed and hence it is said that the resistance of the device has been decreased.
3.5 Detection of Sudden Change in Light Intensity (Z-Score Analysis)Z-score analysis is used for anomaly detection. Anomaly here means a variable's value (light intensity of the surroundings) going beyond a certain range of values. The range of values is called bounds (upper bound and lower bound). These bounds are calculated using the input values, frame size and multiplication factor. The frame size is the minimum number of input values needed for Z-score analysis and the multiplication factor determines the closeness of the bounds to the input values curve.
Given above is the formula to calculate the bounds. Here the input is represented as 'Vi', 'r' denotes the frame size and 'C' is the multiplication factor. Firstly we calculate the mean (Mn) of the input values (for every new input, the mean is calculated again). The variation of each input value (from the mean) is given as (Vi - Mn)^2. The Z-score (Zn) is calculated as shown above ( square root of the mean of the variation of each input value multiplied by the multiplication factor). The bounds are represented as 'Tn' and the upper bound is calculated as (Vi + Zn) and the lower bound is calculated as (Vi - Zn).
The frame size and multiplication factor are determined using trial-and-error method.
4. Configuration FileDigital ocean droplet and ubuntu server have been used to make this project. IP address obtained on the digital ocean droplet dashboard is used in PuTTY configuration page to login. Python codes are run in this server.
In this project two python files namely conf.py (configuration file) and lightt.py are created.
4.1 Conf.py, configuration fileFollowing is the configuration file (named as conf.py):
""" BOLT PLANT BOT CONFIGURATIONS """
bolt_api_key = "XXXXXXXX-a74d-66cd-777e-baXXXXXXXXXX"
device_id = "BOLTXXXXXXX"
telegram_chat_id = "@plant_light_monitor"
telegram_bot_id = "bot2205643668:BBCBeNETRLie9oSHmmXXXXXXXXXXXXXXXXX"
critical_threshold = 500
FRAME_SIZE = 100
MUL_FACTOR = 2
telegram_chat_id is obtained from the permanent link of your channel: t.me/XXXXX. In this code enter telegram_chat_id as @XXXXX. telegram_bot_id is the token obtained from BotFather, when you create your bot. Refer section 3.3.2 for more details. Details on selection of Frame Size and Multiplication Factor can be obtained from section 3.5.
4.2 Main file (light.py)Importing packages:
First import conf (configuration file created earlier), json, time, math and statistics library.
""" IMPORTING PACKAGES """
import requests
import json
import time
import math,statistics
from boltiot import Bolt
mybolt = Bolt(bolt_api_key,device_id)
Bolt python library is imported in the fifth line of the code that helps us in collecting data from the Bolt Cloud.
def get_sensor_value_from_pin(pin):
try:
response = mybolt.analogRead(pin)
data = json.loads(response)
if data["success"] != 1:
print("Request not successfull")
print("This is the response->", data)
return -999
sensor_value = int(data["value"])
return sensor_value
except Exception as e:
print("Oops!...Something went wrong.Please check!!!")
print(e)
return -999
Function, `get_sensor_value_from_pin()` is declared above. This function returns the value of the sensor from the selected pin. If there is an error -999 is declared. -999 is an error response. One parameter(pin) is taken. A request is made to the Bolt Cloud. This helps in collecting the latest sensor value from the selected pin. The function `mybolt.analogRead()` returns the value for the selected pin. `data = json.loads(response)` converts the Bolt Cloud response into a JSON object. The Bolt Cloud returns 1 if the request made is successful. If the request has failed, value other than 1 is returned.
To check if the response is valid `if data["success"] != "1":` is used. The sensor value obtained is converted to an integer and returned.
Defining functions:
"" FUNCTIONS """
def send_telegram_message(message):
url = "https://api.telegram.org/" + telegram_bot_id + "/sendMessage"
data = {
"chat_id": telegram_chat_id,
"text": message
}
try:
response = requests.request(
"POST",
url,
params=data
)
print("Telegram URL")
print(url)
print("This is the Telegram response")
print(response.text)
telegram_data = json.loads(response.text)
return telegram_data["ok"]
except Exception as e:
print("Error occurred!!! while sending message")
print(e)
return False
The above code defines a function requesting Telegram to send a message to the Telegram channel created earlier. The function `send_telegram_message()` sends a Telegram message to the channel. URL is used so that Telegram can send an alert to the Bot we have created. The data variable is a dictionary that contains the chat ID and text message. Chat ID is used so that Bot can send a message to the channel.
Next, a HTTP request is made using the URL. This request is made to the Telegram servers.
"POST" request holds URL and the data that is under the request. Response from the request is then printed. `telegram_data = json.loads(response.text)` converts the response in the form of text to a JSON. It is then stored in telegram_data. This helps in finding the status of the request. The status of the request is stored in the ‘ok’ field of the telegram_data. This is then returned. The "ok" field consists of a True/False value. If the statement is True a message is sent. try-except block contains the function to find out if there are any errors. If there is an error, False is returned.
def compute_bounds(history_data,frame_size,factor):
if len(history_data)<frame_size :
return None
if len(history_data)>frame_size :
del history_data[0:len(history_data)-frame_size]
The above lines of code defines a function. This function takes 3 input variables i.e., frame_size, history_data, factor and finds out whether enough data has been accumulated. Data accumulation helps in calculating the Z-score. If there is a lot of data, older data is deleted by the code.
Mn=statistics.mean(history_data)
Variance=0
for data in history_data :
Variance += math.pow((data-Mn),2)
Zn = factor * math.sqrt(Variance / frame_size)
High_bound = history_data[frame_size-1]+Zn
Low_bound = history_data[frame_size-1]-Zn
return [High_bound,Low_bound]
The above line of code calculates the mean(Mn) value of the data points that are collected.
Variance of data points is calculated. Data’s Z-score is calculated. With the calculated Z-score, upper and lower threshold bounds can be calculated. They are required to find out if there is an anomaly in the new data point.
Algorithm for Driver code is given below:
""" DRIVER CODE """
history_data=[]
while True:
sensor_value = get_sensor_value_from_pin("A0")
print("The current sensor value is:", sensor_value)
if sensor_value == -999:
print("Request Unsuccessfull")
time.sleep(5)
continue
elif sensor_value == critical_threshold:
print("Check Me")
message = "Alert! Critical point reached " + \
"Current value is " + str(sensor_value)
telegram_status = send_telegram_message(message)
print("Telegram status:", telegram_status)
mybolt.digitalWrite("0", "LOW")
mybolt.digitalWrite("1","100")
time.sleep(1)
mybolt.digitalWrite("1","LOW")
elif sensor_value < critical_threshold:
print("Save me..I am not receiving enough light")
message = "Alert! I need minimum of " + str(critical_threshold) + \
"But Current value is " + str(sensor_value)
telegram_status = send_telegram_message(message)
print("Telegram status:", telegram_status)
mybolt.digitalWrite("0", "HIGH")
mybolt.digitalWrite("1", "HIGH")
time.sleep(1)
mybolt.digitalWrite("1", "LOW")
elif sensor_value > critical_threshold:
print("I am fine...")
message = "I am Fine:) Normal light receiving..."+\
"Current value = " + str(sensor_value)
telegram_status = send_telegram_message(message)
print("Telegram status:", telegram_status)
mybolt.digitalWrite("0", "LOW")
time.sleep(5)
Algorithm for anomaly detection is given below:
#Anomaly detection
response = mybolt.analogRead('A0')
data = json.loads(response)
if data['success'] != 1:
print("There was an error while retrieving the data.")
time.sleep(5)
continue
sensor_value=0
try:
sensor_value = int(data['value'])
except e:
print("There was an error while passing the response: ",e)
continue
bound = compute_bounds(history_data,FRAME_SIZE,MUL_FACTOR)
if not bound:
required_data_count=FRAME_SIZE-len(history_data)
history_data.append(int(data['value']))
time.sleep(5)
continue
try:
if sensor_value > bound[0] :
print("Anomaly Detected")
telegram_status = send_telegram_message("Sudden Increase Anomaly Detected")
elif sensor_value < bound[1]:
print("Anomaly Detected")
telegram_status = send_telegram_message("Sudden Decrease Anomaly Detected")
history_data.append(sensor_value);
except Exception as e:
print ("Error",e)
time.sleep(10)
Comments
Please log in or sign up to comment.