Wifi enabled temperature and humidity sensor and client sending email notifications
description
This project was developed as part of a research to build a temperature automation system for our charming but cold Auckland home. Relying on electric oil heaters as sole source of heating in children's room, the aim was to monitor continuously the temperature at night and to turn on or off the heater according to the measured temperature.The project described in this post does the first half and mode demanding part of the job which is log a temperature, broadcast it to the web using the MQTT protocol through the house's wifi.
A small and cheap ESP8266 Wifi board programmes using the Arduino language reads temperature and humidity through an DHT22 sensor and broadcasts the values to an MQTT server at set intervals.
A custom client written in the java based Processing 3 and running on a computer located anywhere (Macbook in this case) displays the readings and sends notifications by email when the temperature drops or rises past the set point.
A second part of the project will consist of a piece of hardware similar to the temperature sensor but listening to the MQTT topic and triggering a 220V 10A relay according to the temperature value. This is to be covered in a different post.
hardware
Bill of material :
ESP8266DHT11 or 22 temperature and humidity sensor
4.7kOhm resistor
power module 5V to 3.3V
power adapter 220V to 5V
breadboard and jumper wires
for flashing : USB adapter for ESP8266
board schematic
code arduino:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Arduino code | |
// Parameters to be updated to suit one's project: | |
// Wifi credentials | |
// MQTT server credentials (here hivemq is being used) and topic names | |
/* | |
* creates a wifi connection | |
* creates a MQTT connection | |
* subscribes to a topic - no action at this stage on ,essage arrived | |
* reads a DHT humidity and temp sensor connected to pin 2 | |
* publishes the values read | |
* waits for a set time (5 minutes) before reading a new value and publishing | |
*/ | |
// | |
#include "ESP8266WiFi.h"; | |
#include "PubSubClient.h"; | |
#include | |
#define DHT11_PIN 2 | |
#define wifi_ssid "WIFI_SSID" | |
#define wifi_password "WIFI_PASSWORD" | |
#define mqtt_server "broker.hivemq.com" | |
// #define mqtt_user "your_username" | |
// #define mqtt_password "your_password" | |
#define topic1 "TOPIC1" | |
#define topic2 "TOPIC2" | |
WiFiClient espClient; | |
PubSubClient client(espClient); | |
SimpleDHT11 dht11; | |
void callback(char* topic, byte* payload, unsigned int length) { | |
Serial.print("Message arrived in topic: "); | |
Serial.println(topic); | |
Serial.print("Message:"); | |
for (int i = 0; i < length; i++) { | |
Serial.print((char)payload[i]); | |
} | |
Serial.println(); | |
Serial.println("-----------------------"); | |
} | |
void setup() { | |
Serial.begin(115200); | |
setup_wifi(); | |
client.setServer(mqtt_server, 1883); | |
client.setCallback(callback); | |
client.subscribe("XXXTOPIC SUBXXXX"); | |
} | |
void setup_wifi() { | |
delay(10); | |
// We start by connecting to a WiFi network | |
Serial.println(); | |
Serial.print("Connecting to "); | |
Serial.println(wifi_ssid); | |
WiFi.begin(wifi_ssid, wifi_password); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.println(""); | |
Serial.println("WiFi connected"); | |
Serial.println("IP address: "); | |
Serial.println(WiFi.localIP()); | |
} | |
void reconnect() { | |
// Loop until we're reconnected | |
while (!client.connected()) { | |
Serial.print("Attempting MQTT connection..."); | |
// Attempt to connect | |
if (client.connect("TestMQTT")) { //* See //NOTE below | |
Serial.println("connected"); | |
} else { | |
Serial.print("failed, rc="); | |
Serial.print(client.state()); | |
Serial.println(" try again in 5 seconds"); | |
// Wait 5 seconds before retrying | |
delay(5000); | |
} | |
} | |
} | |
//NOTE: if a user/password is used for MQTT connection use: | |
//if(client.connect("TestMQTT", mqtt_user, mqtt_password)) { | |
void pubMQTT(String topic,float topic_val){ | |
Serial.print("Newest topic " + topic + " value:"); | |
Serial.println(String(topic_val).c_str()); | |
client.publish(topic.c_str(), String(topic_val).c_str(), true); | |
} | |
//Variables used in loop() | |
unsigned long t0 = millis()/1000; | |
unsigned long t = millis()/1000; | |
long lastMsg = 0; | |
void loop() { | |
if (!client.connected()) { | |
reconnect(); | |
} | |
int err = 1; | |
int tempTotal = 0; | |
int humiTotal = 0; | |
byte temp, humi; | |
client.loop(); | |
t = millis()/1000; | |
// wait 300 s elapsed before measuring and sending a point | |
if (t - t0 > 60) { | |
//Sample the sensor 4 times to get a stable reading. | |
for (int i=0; i<4; i++) { | |
while (err != 0) { err = dht11.read(DHT11_PIN, &temp, &humi, NULL); } | |
tempTotal += temp; | |
humiTotal += humi; | |
err = 1; | |
delay(1050); | |
} | |
//Divide by 4 to get average reading. | |
tempTotal /= 4; | |
humiTotal /= 4; | |
//Publish Values to MQTT broker | |
pubMQTT(topic1,tempTotal); | |
pubMQTT(topic2,humiTotal); | |
t0 = t; | |
} | |
} |
code processing:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Processing 3 code : requires installation of Processing on any platform, Windows, OSX, Linux to run | |
// Parameters to be updated to suit one's project: | |
// 1. MQTT server (your preferred MQTT services broker). We use "mqtt://broker.hivemq.com" which is a public, free however non secure provider perfect for testing purpose. | |
//2. "MQTT topic", "TOPIC 1", "TOPIC 2" : name of the topic used in the arduino code to publish and in the Processing code to subscribe. Form will be: generic_topic_name/location/sub_location/sensor | |
// 3. credentials of the email SMTP server and account to be used. | |
import java.util.*; | |
import mqtt.*; | |
import javax.mail.*; | |
import javax.mail.internet.*; | |
import javax.activation.*; | |
MQTTClient client; | |
String temp=""; | |
float temp_float[] = new float[] {0,0}; | |
float diff[] = new float[] {0,0}; | |
Date date[] = new Date[] {new Date(), new Date()}; | |
// declare the set point for temperature (here 18degC) | |
int treshold = 18; | |
void setup() { | |
size(150, 120); | |
background(0); | |
client = new MQTTClient(this); | |
//replace with MQTT service provider : | |
client.connect("mqtt://broker.hivemq.com", "processing"); | |
// replace TOPIC1 with the temperature topic name: | |
client.subscribe("TOPIC1"); | |
// replace TOPIC2 with the humidity topic name : | |
client.subscribe("TOPIC2"); | |
} | |
//creates a window, black background to display values as they arrive: | |
void draw() { | |
fill(0); | |
rect(0,0,width,height); | |
fill(255); | |
textSize(26); | |
text(temp, 20,60); | |
text("Ā°C",100,60); | |
textSize(12); | |
text(""+date[1],2,110); | |
} | |
//for testing purposeonly, publishes a value on the topic below the threshold if any key is pressed - keep commented if not testing | |
void keyPressed() { | |
// client.publish("TOPIC1", "16.0"); | |
} | |
//callback function called each time a message is received on a subscribed client | |
void messageReceived(String topic, byte[] payload) { | |
if(topic.equals("TOPIC1")){ | |
//stores payload as String | |
temp = new String(payload); | |
//converts payload to integer | |
temp_float[1] = new Float(temp); | |
//calculates difference with treshold for notification | |
diff[1] = temp_float[1] - treshold; | |
date[1] = new Date(); | |
// displays topic, value and time in console | |
println(date[1] + ": new message: " + topic + ":" + new String (payload)); | |
println("difference to "+treshold+ "Ā°C = "+ diff[1]); | |
// checks if notification required and notifies | |
if (diff[1] < 0 && diff[0]>=0) { | |
SendEmail("temperature decreasing: " + temp + "Ā°C at " + date[1] ); | |
println("Email sent"); | |
} | |
//check if notification required for increasing value. Uses hysteresis of "1" to prevent over notification | |
if (diff[1] >= 1 && diff[0] < 1) { | |
SendEmail("temperature increasing: " + temp + "Ā°C at " + date[1]); | |
println("Email sent"); | |
} | |
//stores the n-1 values to be used next time for assessing trend and change | |
temp_float[0] = temp_float[1]; | |
diff[0] = diff[1]; | |
date[0] = date[1]; | |
} | |
} | |
// Email generation procedure - written to use a Yahoo! account. Can be updated to use any smtp provider- | |
//Note; with gmail, gmail detects that the email is generated by a programme and gmail security settings do not allow it by default. | |
public static void SendEmail(String t) { | |
//Get the session object designed to use a Yahoo account to send email. For a different email service provider, adapt the following lines as required | |
Properties props = new Properties(); | |
props.put("mail.smtp.host", "smtp.mail.yahoo.com"); | |
props.put("mail.smtp.socketFactory.port", "465"); | |
props.put("mail.smtp.socketFactory.class", | |
"javax.net.ssl.SSLSocketFactory"); | |
props.put("mail.smtp.auth", "true"); | |
props.put("mail.smtp.port", "465"); | |
Session session = Session.getDefaultInstance(props, | |
new javax.mail.Authenticator() { | |
protected PasswordAuthentication getPasswordAuthentication() { | |
return new PasswordAuthentication("EMAIL_SENDER@yahoo.com","PASSWORD"); | |
} | |
}); | |
//Compose the message | |
try { | |
Message message = new MimeMessage(session); | |
message.setFrom(new InternetAddress("EMAIL_SENDER@yahoo.com")); | |
message.setRecipients(Message.RecipientType.TO, | |
InternetAddress.parse("EMAIL_RECEPIENT@XXX.XX")); | |
message.setSubject(t); | |
message.setText(t); | |
Transport.send(message); | |
System.out.println("Done"); | |
} catch (MessagingException e) {e.printStackTrace();} | |
} |
Sourcing components
Components used for the project:Procured in New Zealand through http://breadboards.co.nz
total cost under 15 NZD, excluding 5V power supplied (reused a spare phone charger and USB cable)
Further developments
hardware : use temp sensor ds18b20 - cheaphardware : source readily assembled boards with DHT11, power supply and slot for connecting ESP2866 link
hardware : create a similar module with a relay (220V 10A) to control a heater using readily available modules like this one link
Credits
Hardware inspired for project example on http://breadboards.co.nz Thanks for their site and selection of products.Processing : https://processing.org/reference/
Arduino : https://www.arduino.cc/reference/en
Comments
Post a Comment