Reading a DHT11 to a file Disclaimer: not a Pythonista, first actual Python programme written right here.



I'm reading a DHT11 sensor from GPIO pin 4 on my Raspberry Pi (thanks Thomas Ward for sending the RPi to me), and I want to log it to a file which will later be parsed into a web-page.

So I wrote the following Python script which is called by a Cron job every minute, and it reads the sensor 5 times then logs the average, min and max to a file for humidity and temperature.

Without further ado, here's my crap:

#!/usr/bin/python

import sys
import Adafruit_DHT
import time

def getLine(array):
    return str(sum(array) / float(len(array))) + "," + str(min(array)) + "," + str(max(array))

sensor = Adafruit_DHT.DHT11
gpio = 4

h = []
t = []

count = 5
date = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())

for num in range(count):
    th, tt = Adafruit_DHT.read_retry(sensor, gpio)
    h.append(th)
    t.append(tt)

with open("MainLog.txt", "a") as file:
    file.write(date + ": ")
    # Write Humidity data
    file.write(getLine(h))
    file.write(" | ")
    file.write(getLine(t))
    # Write line break
    file.write("\n")


I have no idea how "good" or "bad" it is, if it were C# I would know but it's not. All suggestions welcome.

When I get my new hardware (looks like two-three days from now) I'm going to be adding a BMP180 sensor (barometric pressure/altitude).

The Adafruit_DHT library is on GitHub: https://github.com/adafruit/Adafruit_Python_DHT



I'm going to be replacing this with a DHT22, but that's one LoC change:


sensor = Adafruit_DHT.DHT11



To:

sensor = Adafruit_DHT.DHT22
Here is a list of things I would improve:


define constants in upper-case (PEP8 reference)
put the main program logic into the if __name__ == '__main__': to avoid it being executed on import
naming according to PEP8 - getLine() to get_line() (or even better name would be something like get_stats())
remove unused sys import
follow the PEP8 import organization guidelines
use _ as a throw-away variable name (instead of num)
use str.format() instead of string concatenation 
use more meaningful variable names 


The code after the suggested fixes applied:

#!/usr/bin/python
import time

import Adafruit_DHT


SENSOR = Adafruit_DHT.DHT11
GPIO = 4
MEASUREMENTS_COUNT = 5


def get_stats(array):
    average = sum(array) / float(len(array))
    return "{average},{min},{max}".format(average=average, min=min(array), max=max(array))


if __name__ == '__main__':
    date = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())

    humidities = []
    temperatures = []
    for _ in range(MEASUREMENTS_COUNT):
        humidity, temperature = Adafruit_DHT.read_retry(SENSOR, GPIO)
        humidities.append(humidity)
        temperatures.append(temperature)

    with open("MainLog.txt", "a") as file:
        file.write("{date}: {th} | {tt}\n".format(date=date, th=get_stats(humidities), tt=get_stats(temperatures)))


By the way, I've done something similar, but using the Particle Photon and both DHT11 and BMP180, getting the average values from both sensors - I was surprised how different the values from these sensors were (may be I did something wrong there).



I was also thinking about improving the way stats are formed and using a namedtuple for it:

from collections import namedtuple

Stats = namedtuple("Stats", ["average", "min", "max"])


Then, the get_stats could be:

def get_stats(measurements):
    return Stats(average=sum(measurements) / float(len(measurements)),
                 min=min(measurements),
                 max=max(measurements))


which will change the way we output to the file:

message_template = "{date}: {th.average}, {th.min}, {th.max} | {tt.average}, {tt.min}, {tt.max}\n"
with open("MainLog.txt", "a") as file:
    file.write(message_template.format(date=date, th=get_stats(humidities), tt=get_stats(temperatures)))


This looks a little bit more pythonic - I like the way we construct a message in a single place and keep the stats in a more cleaner manner.