Python Programming Tutorial: Getting Started with the Raspberry Pi

Pages
Contributors: Shawn Hymel
Favorited Favorite 30

Experiment 5: File Reading and Writing

Let's take our previous example (taking measurements from an I2C device) and log them to a file! This can be incredibly useful if you are trying to measure the temperature (light, humidity, wind speed, air pressure, people entering your room, or really anything) and want to see how it changes over the course of minutes, hours, or days.

Recommended Reading

Hardware Connections

We'll use the same circuit as last time.

  • Connect SDA1 (GPIO2, pin 3) to SDA on the TMP102
  • Connect SCL1 (GPIO3, pin 5) to SCL on the TMP102
  • Connect power (3.3 V) to VCC on the TMP102
  • Connect ground (GND) to GND on the TMP102

Connecting through a Pi Wedge:

Fritzing diagram of using a Pi Wedge to connect to a TMP102 temperature sensor

Connecting directly to the Raspberry Pi:

Fritzing diagram of Raspberry Pi connected to a TMP102 temperature sensor

Code: Measure and Log Temperature to a File

We'll turn our previous code into a module for use to use. Change the code in tmp102.py to the following:

tmp102.py

language:python
import smbus

# Module variables
i2c_ch = 1
bus = None

# TMP102 address on the I2C bus
i2c_address = 0x48

# Register addresses
reg_temp = 0x00
reg_config = 0x01

# Calculate the 2's complement of a number
def twos_comp(val, bits):
    if (val & (1 << (bits - 1))) != 0:
        val = val - (1 << bits)
    return val

# Read temperature registers and calculate Celsius
def read_temp():

    global bus

    # Read temperature registers
    val = bus.read_i2c_block_data(i2c_address, reg_temp, 2)
    # NOTE: val[0] = MSB byte 1, val [1] = LSB byte 2
    #print ("!shifted val[0] = ", bin(val[0]), "val[1] = ", bin(val[1]))

    temp_c = (val[0] << 4) | (val[1] >> 4)
    #print (" shifted val[0] = ", bin(val[0] << 4), "val[1] = ", bin(val[1] >> 4))
    #print (bin(temp_c))

    # Convert to 2s complement (temperatures can be negative)
    temp_c = twos_comp(temp_c, 12)

    # Convert registers value to temperature (C)
    temp_c = temp_c * 0.0625

    return temp_c

# Initialize communications with the TMP102
def init():

    global bus

    # Initialize I2C (SMBus)
    bus = smbus.SMBus(i2c_ch)

    # Read the CONFIG register (2 bytes)
    val = bus.read_i2c_block_data(i2c_address, reg_config, 2)

    # Set to 4 Hz sampling (CR1, CR0 = 0b10)
    val[1] = val[1] & 0b00111111
    val[1] = val[1] | (0b10 << 6)

    # Write 4 Hz sampling back to CONFIG
    bus.write_i2c_block_data(i2c_address, reg_config, val)

    # Read CONFIG to verify that we changed it
    val = bus.read_i2c_block_data(i2c_address, reg_config, 2)

Create a new file and enter the following code. Give the file a name such as templogger.py.

templogger.py

language:python
import time
import datetime
import tmp102

filename = "temp_log.csv"

# Create header row in new CSV file
csv = open(filename, 'w')
csv.write("Timestamp,Temperature\n")
csv.close

# Initialize communication with TMP102
tmp102.init()

# Sample temperature every second for 10 seconds
for t in range(0, 10):

    # Construct CSV entry from timestamp and temperature
    temp_c = str(round(tmp102.read_temp(), 2))
    entry = str(datetime.datetime.now())
    entry = entry + "," + temp_c + "\n"

    # Log (append) entry into file
    csv = open(filename, 'a')
    try:
        csv.write(entry)
    finally:
        csv.close()

    # Wait 1 second before sampling temperature again
    time.sleep(1)

# When all the writing has been completed, print the CSV contents
csv = open(filename, 'r')
print(csv.read())
csv.close()

Run the temperature logger with python templogger.py. You should see nothing happen for 10 seconds as the program reads the temperature once every second. For fun, try breathing on the temperature sensor to affect the data! After those 10 seconds, the collection should be complete, and the contents of temp_log.csv will be printed to the screen.

You can view the contents of the log by entering cat temp_log.csv into the console.

Logging temperature and displaying it on a Raspberry Pi

Code to Note:

If you remember from our Programming in Python section, we covered how to create modules. Modules let you reuse code that exist in other files. In our case, we put the "measure temperature" section of the tmp102.py code into a function definition so that we may call it from another file.

In our main program (templogger.py), we imported our own module with import tmp102. Notice that we left out the .py suffix--Python knows to look for a .py file.

You'll also notice that whenever we open a file for reading or writing, we close it as soon as we can. It's generally not good practice to open a file and leave it open. If your program or operating system crashes while the file is open, you could potentially corrupt the file (or worse, the whole filesystem).

For extra protection, we add the writing section in a try block:

language:python
try:
    csv.write(entry)
finally:
    csv.close()

Now, if something crashes while the program is trying to write to the file, an exception will be thrown and Python will automatically close the file before exiting.

You can also see that how we access a file is given by the second parameter in the open() function:

  • 'r' - Read
  • 'w' - Write (this will erase the original contents of the file)
  • 'a' - Append (this will keep the original contents and add your additions at the end)

datetime.datetime.now() returns a datetime object, which we convert into a string with str(). Note that this is based on the local time of your Raspberry Pi. You can get a Coordinated Universal Time (UTC) date and timestamp with datetime.datetime.utcnow().

Challenge: Open the temperature log in a spreadsheet program and create a graph showing how the temperature changed over those 10 seconds (for extra credit, change the program to measure temperature over a longer period of time). Hint: Raspbian comes with LibreOffice Calc, a free spreadsheet program. If you use Calc, the Data > Text to Columns function might help you convert your date/timestamps into something usable.

Temperature data logged and displayed as a graph

Headless: If you are using the Raspberry Pi as a headless device, you may want to print the contents of the CSV to the screen, and copy-and-paste them into a spreadsheet program on your host computer.

Solution: There's not really an "answer" to this. Get creative and show off your graphing skills!