Now that we’ve defined the database to save our temperature and humidity values, we need a process to query the sensor and update the database. I also decided to create a log file containing the values as it’s easier to see that the process is working properly in a log file. So our little python script that we used to test the sensors will be updated to save the values in the rrd database, and also write them to a log file.
#!/usr/bin/python3 import os import time import Adafruit_DHT as dht import rrdtool import datetime DHT_SENSOR = dht.DHT22 U_DHT_PIN = 5 D_DHT_PIN = 6 while True:
It starts off the same, except that we need to include some additional modules. I’ve added os, rrdtool, and datetime modules. The constants are defined just as before.
try: f = open('/var/log/temp_humidity.log', 'a+') except: pass
This code opens the log file in append mode so that we can write to it later. It may seem odd to open the file each time through the loop, but this allows log file rotation to work properly. This script only runs every 5 minutes, so opening it within the loop is a reasonable compromise.
# read the upstairs sensor data uh,ut = dht.read_retry(DHT_SENSOR, U_DHT_PIN) # read the downstairs sensor data dh,dt = dht.read_retry(DHT_SENSOR, D_DHT_PIN) if uh is not None and ut is not None and dh is not None and dt is not None:
Querying the sensors is the same as before, but the test for valid values is now done in a single if statement.
# apply correction factor to DHT22 sensor temperature values ut = ut - 0 dt = dt + 0 # apply correction factor to DHT22 sensor humidity values uh = uh - 3.4 dh = dh + 3.4 # convert temp to fahrenheit ut = ut * 9/5.0 + 32 #dt = dt * 9/5.0 + 32 # log values f.write('{0} upstairs {1:0.1f}F {2:0.1f}% downstairs {3:0.1f}C {4:0.1f}%\r\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'), ut, uh, dt, dh)) f.flush() # update database data = 'N:' + '{0:.1f}'.format(ut) + ':' + '{0:.1f}'.format(uh) + ':' '{0:.1f}'.format(dt) + ':' + '{0:.1f}'.format(dh) #print(data) ret = rrdtool.update("%s/temp_humidity.rrd" % (os.path.dirname(os.path.abspath(__file__))),data) if ret: err = rrdtool.error() f.write('{0} {1}\r\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'), err)) f.flush()
And now we get to the meat of the process. I’ve added code that allows you to apply a correction factor to the values before storing them in the database. My humidity sensors were tracking 6.8% apart, and did that consistently for a couple of days. Since they’re lying on the table about 12″ apart while I test this project, and the difference was constant, I chose to reduce the upstairs value and increase the downstairs value by the same amount. The temperature sensors agreed with a about 0.2 degrees so I left the correction at zero for them – at least for now.
Then we log the values to the log file, and the flush command causes the write to happen immediately. Without it the writes are buffered and may be delayed. I prefer that the log file is current.
To update the rrd database, we build a string containing the values. The data elements are separated by colons, and the first element is “N”, which rrdtool translates to a timestamp for “right now”. The four data values are placed in the string in the same order they were defined when we created the rrd database.
The rrdtool.update command references the temp_humidity.rrd database file, and locates the full path to the file. The variable data, containing the string we constructed earlier, is the only other parameter. The return code from the update process is assigned to the variable “ret” which we then test to ensure the result is good. If not, we log the error and execute the flush, to write the error into the log file immediately.
else: f.write('{0} ERROR - failed to retrieve data from temp/humidity sensor\r\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'))) f.flush() dateTimeObj = datetime.now() date_time = dateTimeObj.strftime("%B %-d, %Y at %-I:%M %p") port = 587 # For starttls smtp_server = "smtp.gmail.com" sender_email = "xxxx@xxxxxxxxxxxxxxxxx.com" receiver_email = "xxxx@xxxxxxxxx.com" password = "xxxxxxxxxxxx" message = """\ Subject: Alert - problem reading temp/humidity sensor On {}, there was a problem reading the temperature/humidity sensor. If this is not resolved there will be gaps in the data. """.format(date_time) context = ssl.create_default_context() with smtplib.SMTP(smtp_server, port) as server: #server.ehlo() # Can be omitted server.starttls(context=context) #server.ehlo() # Can be omitted server.login(sender_email, password) server.sendmail(sender_email, receiver_email, message) f.close() time.sleep(300)
This code handles the condition where we do not receive valid values from querying the sensors. First we log the error condition. Then we send an email to the administrator (me) to let me know there has been a problem. Finally, we close the log file and sleep for 300 seconds (5 minutes).
Here’s the complete script. As before, be aware that python is sensitive to indentation and line spacing.
#!/usr/bin/python3 import os import time import Adafruit_DHT as dht import rrdtool import datetime DHT_SENSOR = dht.DHT22 U_DHT_PIN = 5 D_DHT_PIN = 6 while True: try: f = open('/var/log/temp_humidity.log', 'a+') except: pass # read the upstairs sensor data uh,ut = dht.read_retry(DHT_SENSOR, U_DHT_PIN) # read the downstairs sensor data dh,dt = dht.read_retry(DHT_SENSOR, D_DHT_PIN) if uh is not None and ut is not None and dh is not None and dt is not None: # apply correction factor to DHT22 sensor temperature values ut = ut - 0 dt = dt + 0 # apply correction factor to DHT22 sensor humidity values uh = uh - 3.4 dh = dh + 3.4 # convert temp to fahrenheit ut = ut * 9/5.0 + 32 #dt = dt * 9/5.0 + 32 # log values f.write('{0} upstairs {1:0.1f}F {2:0.1f}% downstairs {3:0.1f}C {4:0.1f}%\r\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'), ut, uh, dt, dh)) f.flush() # update database data = 'N:' + '{0:.1f}'.format(ut) + ':' + '{0:.1f}'.format(uh) + ':' '{0:.1f}'.format(dt) + ':' + '{0:.1f}'.format(dh) #print(data) ret = rrdtool.update("%s/temp_humidity.rrd" % (os.path.dirname(os.path.abspath(__file__))),data) if ret: err = rrdtool.error() f.write('{0} {1}\r\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'), err)) f.flush() else: f.write('{0} ERROR - failed to retrieve data from temp/humidity sensor\r\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'))) f.flush() dateTimeObj = datetime.now() date_time = dateTimeObj.strftime("%B %-d, %Y at %-I:%M %p") port = 587 # For starttls smtp_server = "smtp.gmail.com" sender_email = "xxxx@xxxxxxxxxxxxxxxxx.com" receiver_email = "xxxx@xxxxxxxxx.com" password = "xxxxxxxxxxxx" message = """\ Subject: Alert - problem reading temp/humidity sensor On {}, there was a problem reading the temperature/humidity sensor. If this is not resolved there will be gaps in the data. """.format(date_time) context = ssl.create_default_context() with smtplib.SMTP(smtp_server, port) as server: #server.ehlo() # Can be omitted server.starttls(context=context) #server.ehlo() # Can be omitted server.login(sender_email, password) server.sendmail(sender_email, receiver_email, message) f.close() time.sleep(300)
Next, the pretty part. We’ll build a script to generate graphs using the data we’ve so carefully saved.