Esp8266 Temperature Sensors IoT
by dsigurdsson in Circuits > Arduino
381 Views, 0 Favorites, 0 Comments
Esp8266 Temperature Sensors IoT
Been playing with the idea of having temperature sensors around the house for a while, started about 6 years ago and made a RasberryPi 1 with 3 external DS18B20 sensors to read temperature at three different places, and always thought how can I do this simply without wires all over the place.
Put it on hold (as many of us tend to do with alot of projects)
Fast forward 6 years and I suddenly got the urge back to finish the project, but this time I decided to use D1 mini clones with DS18B20 sensors.
At first I was thinking about using MQTT to send the data, but after some testing I decided not to use it, and instead have a custom python script running on a VPS that puts it in a MySQL database.
D1 mini sends a secret key, temperature reading and it's name to the server. That then gets inputted into a MySQL database, then it goes to sleep for just under 5minutes before waking up and doing everything again.
Supplies
Items needed:
1x D1 Mini esp8266 https://www.aliexpress.com/item/32651747570.html
1x DS18B20 Temperature sensor https://www.aliexpress.com/item/2003096698.html
1x Prototype board https://www.aliexpress.com/item/32426914735.html
1x 4.7kOhm resistor https://www.aliexpress.com/item/32862361762.html
VPS https://m.do.co/c/539bb132845e (affiliate link, you get $200 credit after adding payment over 60 days)
Some small wires and heatshrink tube
Optional:
1x D1 mini Battery shield https://www.aliexpress.com/item/32792842042.html
1x Single cell 18650 battery holder https://www.aliexpress.com/item/1005001874531854.html
Waterproof DS18B20 https://www.aliexpress.com/item/32342208694.html
Tools
Soldering tools
Solder
Wirecutters
Getting Software Ready
On a linux based machine install python3, apache webserver, Grafana and MySQL.
Make sure to install all required libraries for everything.
Save the server.py into /usr/sbin and make sure to make it executable. (chmod +x /usr/sbin/server.py)
#!/usr/bin/env python3
import socket
import ssl
import MySQLdb
# Set the secret key
secret_key = b'Really_secret_key'
# Create a listening socket on port 8888
host = '0.0.0.0'
port = 8888
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, port))
sock.listen(5)
print(f'Listening on port {port}...')
# Connect to MySQL
host = 'localhost'
dbname = 'temperature'
username = 'sql_user'
password = 'sql_pass'
db = MySQLdb.connect(host=host, user=username, passwd=password, db=dbname)
db.set_character_set('utf8mb4')
cursor = db.cursor()
print('Connected to MySQL...')
# Handle incoming connections
while True:
conn, addr = sock.accept()
print('Client connected')
try:
data = conn.recv(1024).decode('latin-1')
print(f'Incoming data {data}')
if ',' not in data:
continue # data does not contain expected values, so skip to next iteration
sec_key, user_name, user_temp = data.split(",")
if sec_key != secret_key.decode() or not user_name or not user_temp:
print('Error: secret key missing or incorrect, or username and temp parameters are required')
continue
cursor.execute(f"INSERT INTO temp_fl (user_name, temp) VALUES ('{user_name}', '{user_temp}')")
db.commit()
print(f"Inserted row with ID {cursor.lastrowid}")
except (ssl.SSLError, ConnectionResetError):
pass
conn.close()
Create your database in MySQL and create table
CREATE DATABASE temperature;
CREATE TABLE temp_fl (
id INT AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(50),
temp DECIMAL(5,2),
input_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
And upload the sketch to your D1 mini
#include <OneWire.h>
#include <DallasTemperature.h>
#include <ESP8266WiFi.h>
// Data wire is connected to D5
#define ONE_WIRE_BUS D5
// WiFi settings
const char* ssid = "YourSSID";
const char* password = "WifiPassword";
const char* server = "VPSServerAddress";
const int port = 8888;
const String secret_key = "Really_secret_key";
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass oneWire reference to DallasTemperature library
DallasTemperature sensors(&oneWire);
void setup() {
Serial.begin(9600);
// Connect to WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi!");
// Initialize the DS18B20 sensor
sensors.begin();
}
void loop() {
// Request temperature readings from all DS18B20 sensors on the bus
sensors.requestTemperatures();
// Get the temperature value from the DS18B20 sensor on D5
float temperature = sensors.getTempCByIndex(0);
// Get the username value
String username = "NameOfSensor-Location";
// Create the TCP socket and connect to the server
WiFiClient client;
if (!client.connect(server, port)) {
Serial.println("Failed to connect to server");
return;
}
// Send the temperature and username data to the server
//client.print(username + "," + String(temperature));
// Send the temperature and username data to the server with secret key
String data = secret_key + "," + username + "," + String(temperature);
client.print(data);
// Close the TCP socket
client.stop();
Serial.println(temperature);
ESP.deepSleep(295e6); //Deepsleep for 4min55sec, allow some time to connect to wifi before performing task
}
Soldering and Putting Everything Together
Now comes the fun part, soldering.
I used male headers on the D1 mini and female headers on the prototype board so I could remove the D1 mini with ease and re-flash/program or do whatever I wanted with it, without worrying about removing the reset wire or resistor.
First solder the male headers to the D1 mini.
Next, with the correct spacing, solder the female headers.
Connect the 4.7kOhm resistor between 3.3V and D5.
Solder a wire jumper between RST and D0 (this will make it wake up from deepsleep)
Solder wires onto the feet of the DS18B20, make sure you have the correct pinout.
Now solder the wires to the prototype board. GND goes to G, DQ goes to D5 and VDD goes to 3.3V
When plugging the D1 mini onto the prototype board, make sure of your pins! you do not want to put it upside down!
Stick in a nice box or not and you are ready to power it up.
Running
From your terminal start the server.py, you should now see data coming in.
Configure Grafana to your likings, wether it be a graphs, lines og gauges.
Conclusion
If you plan on using this outdoors like I did you could add the D1 mini battery shield and connect an 18650 battery to it, with deepsleep (even with a v2 Mini) it could run for a long time.
With a 1800mAh battery it could run without problem for up to 25 days. Or you could add a small solar panel to it, and never have to worry about it again.
Great site to see IoT Battery Life https://of-things.de/battery-life-calculator.php
And to get better and more accurate readings outdoors, replace the To-92 DS18B20 with a waterproof DS18B20
I'm 100% sure the code could use some work to be more optimized and function better, for example I had some issues where the server.py seemed to stop inserting into MySQL, and since I'm lazy I just use a python script that checks and sees if we have any missing data in the past 10 minutes.
/usr/sbin/watchdog.py
#!/usr/bin/env python3
import time
import subprocess
import pymysql
# MySQL database connection details
db_host = "localhost"
db_user = "sql_user"
db_pass = "sql_pass"
db_name = "temperature"
table_name = "temp_fl"
field_name = "input_time"
# Command to start the server
start_command = "python3 /usr/sbin/server.py &"
# Command to kill the server
kill_command = "pkill -f 'python3 /usr/sbin/server.py'"
# Time to wait before checking again (in seconds)
check_interval = 600
def check_database():
try:
# Connect to the database
conn = pymysql.connect(host=db_host, user=db_user, password=db_pass, db=db_name)
# Create a cursor object
cursor = conn.cursor()
# Query to check the latest entry in the table
query = "SELECT %s FROM %s ORDER BY %s DESC LIMIT 2" % (field_name, table_name, field_name)
# Execute the query
cursor.execute(query)
# Get the latest input time
latest_input_time = cursor.fetchone()[0]
# Calculate the time difference
time_difference = time.time() - latest_input_time.timestamp()
# Check if the time difference is greater than 10 minutes
if time_difference > check_interval:
# Kill the server process
subprocess.run(kill_command, shell=True)
# Start the server process
subprocess.Popen(start_command.split())
except pymysql.Error as e:
print("MySQL Error [%d]: %s" % (e.args[0], e.args[1]))
finally:
# Close the database connection
conn.close()
if __name__ == '__main__':
while True:
check_database()
time.sleep(check_interval)
So that concludes it, if anyone has any question or suggestions on improvement please reach out.
Update
After running the system for a few days I started to notice I was getting weird spikes on two of the sensors, and what was even more weird is they were happening at the same time on both sensors, with exactly 2hours and 10min between.
Both were directly connected to 5V PSU, while two others, were running un a battery and not showing said spikes.
Added a battery to another one, but was still getting spikes, switched locations (to eliminate any localised interference) but still spikes.
Last thing to try was to increase the length of the wires going from the D1 mini to the DS18B20, and low and behold, no more spikes.
Working on an updated version that stores the RSSI value, along with voltage of the battery and a secondary value, such as an extra temp sensor or even humidity.