Often when designing Data acquisition systems, such as plant health monitoring in which case, the sensors are placed on-site, knowing the weather conditions may help in predicting the behaviour of other data and changes in physical requirements, if any.
The project involves the design of an IoT based solution to monitor the data obtained from the sensors as well as weather forecasts predicted for a particular region. This could help in connecting multiple sensors to a system and obtaining the data on a central display.
The system consists of a transmitter and a receiver section. A device runs the script to control the data being displayed at the end of the receiver sub-system.
The transmitter consists of a microcontroller(such as Arduino UNO) with ADC channels. The sensors can then be connected to the controller via these channels or other GPIO pins present on the board. The microcontroller then periodically reads these sensor values and sends the data to an ESP8266 Wi-Fi module (such as 12E, 12F, 01 or NodeMCU) via serial UART protocol. The ESP module connects to a Wi-Fi access point (hotspot/router) and sends the data to a Thingspeak channel.
The device running the main script periodically collects the data entries from the Thingspeak channel and weather forecast data from other sources such as OpenWeathermap and AccuWeather via API calls and then sends them to Bolt cloud for serial transmission via the Bolt IoT module. Another microcontroller (such as Arduino UNO) is connected serially to the Bolt IoT module, to read the data transmitted by the module and then to display the same on a display unit such a 16x2 LCD display. The main script may also update the Thingspeak channel with the weather data so that the past entries can be accessed from Thingspeak.
Steps to build the system:1. Getting API keys:The above system requires API keys from the vendors to request for their respective services.
Note: Do not share or disclose your API keys. In case, they get compromised, reset the keys immediately.
- A. Bolt Cloud:
The Bolt Cloud is required to communicate with the Bolt IoT module. After purchasing the module (link) and downloading the BoltIoT app from Google Play (link) or App Store (link), follow the simple steps here for setting up the Bolt WiFi module and creating your Bolt cloud account.
Login to Bolt cloud (https://cloud.boltiot.com) using your account. Copy your device ID from the dashboard and API key from the API credentials after enabling them.
- B. Thingspeak:
Create your Thingspeak account and login. Create a new channel, and name the fields accordingly.
Click on the 'API keys' tab and copy the read and write API keys for the channel.
- C. OpenWeatherMap:
Go to https://openweathermap.org/api and click on subscribe under 'Hourly Forecast'. From the table, under the 'Free' column, click on 'Get API key and start'. Click on signup and register with your credentials. Log in and click on the API keys tab. Copy the key from the screen.
- D. AccuWeather:
Go to https://developer.accuweather.com/apis and register with your credentials. Log in and click on 'My Apps'. Click on 'Add a new app'. Create an app accordingly.
Once approved, click on the app's name and copy the API key.
2. Programming the devices(using Arduino IDE):- A. Receiver Arduino UNO:
Refer code explanation here.
#include <LiquidCrystal.h>
#define MAX_DATA 4
const int rs = 12, en = 11, d4 = 10, d5 = 9, d6 = 8, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
lcd.begin(16,2);
delay(200);
Serial.begin(9600);
}
int digit=0,i=0,val,sign=1;
int data[MAX_DATA];
char message[16];
void loop() {
while(Serial.available()>0) {
char inChar = Serial.read();
if (isDigit(inChar)) {
val = int(inChar)-48;
digit=digit*10+val*sign;
}
else if(inChar==' ' || (inChar=='\n' && i==MAX_DATA-1)) {
data[i]=digit;
i++;
digit=0;
}
else if(inChar =='\n') {
lcd.setCursor(0,0);
sprintf(message,"L:%dlux T:%dC",data[0],data[1]);
lcd.print(message);
lcd.setCursor(0,1);
if(data[3]==0)
sprintf(message,"Maximum temp:%dC",data[2]);
else if(data[3]==1)
sprintf(message,"Rain chances:%d%c",data[2],37);
else if(data[3]==2)
sprintf(message,"Minimum temp:%dC",data[2]);
lcd.print(message);
i=0;
digit=0;
}
else if(inChar=='-')
sign=-1;
}
}
- B. Transmitter Arduino UNO:
Refer code explanation here.
#define ADC_size 10;
String light1,temp1;
int m=0,light,temp;
float a=0.555,b=-19.82;
void setup() {
Serial.begin(9600);
}
void loop() {
light=analogRead(A0)*a+b;
temp=analogRead(A1)*500/(pow(2,ADC_size)-1);
light1=String(light);
m=light1.length();
while(m<3){
light1=String(0)+light1;
m++;
}
if(temp<0)
temp1=String('-')+String(abs(temp));
else
temp1=String(temp);
m=temp1.length();
while(m<2){
temp1=String(0)+temp1;
m++;
}
if(light1.length()==3 && temp1.length()==2)
Serial.println("*"+light1+temp1+"#");
delay(30000);
}
- C. Transmitter ESP8266:
In the case of using the ESP8266-12E module, connect the components as shown. In Arduino IDE under File preferences, paste 'http://arduino.esp8266.com/stable/package_esp8266com_index.json' and select 'Generic ESP8266 module' as the board.
Fritzing file here.
Note: Use a separate 3.3V power supply for ESP8266, as UNO cannot provide high current.
Hold the flash key down and click the reset key to enter the programming mode.
Refer code explanation here.
#include <ESP8266WiFi.h>
String apiKey = "";
const char* ssid = "";
const char* password = "";
const char* server = "api.thingspeak.com";
int data1, data2, data3, data4, data5, ok;
WiFiClient client;
unsigned char buff[10], i;
String buffer1, buffer2;
void setup() {
Serial.begin(9600);
delay(10);
WiFi.begin(ssid, password);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
}
void loop() {
if (Serial.available() > 0) {
delay(100);
while (Serial.available() > 0) {
buffer1 = Serial.readString();
if (buffer1[0] == '*') {
if (buffer1[6] == '#') {
Serial.println(buffer1);
data1 =((buffer1[1]-0x30)*100+(buffer1[2]-0x30)*10+(buffer1[3]-0x30));
if(buffer1[4]=='-')
data2=-(buffer1[5]-0x30);
else
data2 =((buffer1[4]-0x30)*10+(buffer1[5]-0x30));
}
}
}
}
if (client.connect(server, 80)) {
String postStr = apiKey;
postStr += "&field1=";
postStr += String(data1);
postStr += "&field2=";
postStr += String(data2);
postStr += "\r\n\r\n";
client.print("POST /update HTTP/1.1\n");
client.print("Host: api.thingspeak.com\n");
client.print("Connection: close\n");
client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(postStr.length());
client.print("\n\n");
client.print(postStr);
Serial.println(postStr);
}
client.stop();
Serial.println("Waiting...");
delay(20000);
}
3. Assembling the hardware:- A. Transmitter:
Fritzing file here.
Note: Use a separate 3.3V power supply for ESP8266, as UNO cannot provide high current.
- B. Receiver:
Fritzing file here.
On Linux, open Terminal or shell and run the command:
sudo pip3 install boltiot
Note: Windows users may use the command prompt for the same. Also, Android phone users may download Pydroid 3 from Google Play and run the command from the app's terminal.
- A. Configuration file(conf.py):
API_KEY = '' #BOLT API key(36)
DEVICE_ID = '' #BOLT device ID(11)
CHANNEL_ID='' #Thingspeak Channel ID(6)
WRITE_KEY='' #Thingspeak Channel Write key(16)
READ_KEY='' #Thingspeak Channel Read key(16)
WEATHER_KEY_OW='' #Openweather API key(32)
WEATHER_KEY_AW='' #Accuweather API key(32)
LOCATION_ID_AW='' #Accuweather city code(6)
CITY_NAME='' #Openweather city name
LOCATION_ID_OW='' #Openweather city code(alternative)(7)
TIME_DIFF=19800 #For IST, GMT+5:30 hours=19800 seconds
- B. Main script:
Refer code explanation here.
from boltiot import Bolt
from datetime import datetime,timedelta
import conf,time,re
import urllib3,json,requests
mybolt=Bolt(conf.API_KEY,conf.DEVICE_ID)
http=urllib3.PoolManager()
def fetch_data(channel_id,read_key):
try:
url="http://api.thingspeak.com/channels/%s/feeds/last.json?api_key=%s" %(channel_id,read_key)
conn=http.request('GET',url)
response=conn.data.decode('utf8')
data=json.loads(response)
conn.close()
last_write=list(filter(None,re.split("[-TZ:]+",data['created_at'])))
last_write.append(1)
temp=[]
for i in last_write:
temp.append(int(i))
p=datetime(temp[0],temp[1],temp[2],temp[3],temp[4],temp[5],temp[6])
p=p+timedelta(seconds=conf.TIME_DIFF)
dt=datetime.today()
return(int(data['field1']),int(data['field2']),(dt-p).seconds)
except Exception as e:
print("Could not fetch data from Thingspeak")
print(e)
return(-999,-999,-999)
def fetch_openweather(city_name):
try:
base_url="http://api.openweathermap.org/data/2.5/forecast?"
complete_url = base_url + "appid=" + conf.WEATHER_KEY_OW + "&q=" + city_name
response=requests.get(complete_url)
data=response.json()
temp_min=int(data['list'][1]['main']['temp_min']-273.15)
temp_max=int(data['list'][1]['main']['temp_max']-273.15)
response.close()
return(temp_max,temp_min)
except Exception as e:
print("Could not fetch data from Openweather")
print(e)
return(-999,-999)
def fetch_accuweather(location_id,api_key):
try:
url='http://dataservice.accuweather.com/forecasts/v1/hourly/1hour/%s?apikey=%s&details=true' %(location_id,api_key)
conn=http.request('GET',url)
response=conn.data.decode('utf8')
data=json.loads(response)
conn.close()
return(int(data[0]['RainProbability']))
except Exception as e:
print("Could not fetch data from Accuweather")
print(e)
return(-999)
def post_data(content,write_key):
try:
url='http://api.thingspeak.com/update'
key={'api_key':write_key}
payload=dict(key,**content)
resp=requests.post(url,params=payload)
resp.close()
except Exception as e:
print("Could not write data to Thingspeak")
print(e)
def write_to_bolt(data):
try:
resp=mybolt.serialBegin(9600)
data2=json.loads(resp)
if(data2['success']==0):
print('Could not communicate with Bolt')
else:
mybolt.serialWrite(str(data['field1'])+" "+str(data['field2'])+" "+str(data['field3'])+" "+str(data['command'])+" \n")
except Exception as e:
print("Could not write data to Bolt")
print(e)
def main():
dt=datetime.today()
waits=120
data3,data4=0,0
while(True):
data={}
time.sleep(30)
waits+=1
data['field1'],data['field2'],time_diff=fetch_data(conf.CHANNEL_ID,conf.READ_KEY)
if(waits>=120):
if(dt.month>2 and dt.month<7):
data3=fetch_openweather(conf.CITY_NAME)[0]
data4=0
elif(dt.month>6 and dt.month<11):
data3=fetch_accuweather(conf.LOCATION_ID_AW, conf.WEATHER_KEY_AW)
data4=1
else:
data3=fetch_openweather(conf.CITY_NAME)[1]
data4=2
waits=0
data['field3']=data3
data['command']=data4
for i in data:
if(data[i]==-999 or time_diff==-999):
continue
write_to_bolt(data)
print(data)
del(data['command'])
if(time_diff<15):
time.sleep(15-time_diff)
time.sleep(30)
waits+=1
post_data(data,conf.WRITE_KEY)
if(__name__=='__main__'):
main()
Observations:- A. Connections:
- B. Entries:
- C. Running the script:
For testing, refer to this page for the examples.
Comments