Using the RPi.GPIO module with Python 3
As stated in the previous article of our furnace control project, Raspian comes pre-installed with a Python module to interact with the GPIO header. However, this module is installed for Python 2.7 only; trying to import RPi.GPIO using Python3 raises an ImportError.
Installing the RPi.GPIO module for Python 3 is actually quite simple.
First of all, before installing any software it’s always a good idea to update repository information. Run this command:
sudo apt update
This updates software repository information: ensures package lists are up to date, and so on. When this command completes, go ahead and install available updates:
sudo apt upgrade
Confirm upgrades when prompted, by entering Y for yes; let it proceed. When updates are finished running, it’s time to install the GPIO module for Python 3:
sudo apt install python3-rpi.gpio
The appropriate packages should download and install. When done, verify that you can import the module using Python 3:
$ python3 Python 3.5.3 (default, Jan 19 2017, 14:11:04) [GCC 6.3.0 20170124] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import RPi.GPIO >>>
As you can see, the “import RPi.GPIO” command returned no output. This is a good sign; it means the module was imported successfully. Now quit the Python prompt:
quit()
Now you can run your GPIO projects with Python 3 if you prefer.
My furnace control script’s Print statements needed some help. One of the most obvious differences (to a beginner like me, at least) between Python 2 and Python 3 lies in the format of print statements. In Python 2, this works:
$ python Python 2.7.13 (default, Nov 24 2017, 17:33:09) [GCC 6.3.0 20170516] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> print "hello world" hello world >>>
Using Python 3, the same command fails.
$ python3 Python 3.5.3 (default, Jan 19 2017, 14:11:04) [GCC 6.3.0 20170124] on linux Type "help", "copyright", "credits" or "license" for more information. >>> print "hello world" File "<stdin>", line 1 print "hello world" ^ SyntaxError: Missing parentheses in call to 'print' >>>
The error message is helpful: we’re missing parentheses. Let’s modify our print statement so Python 3 is happy.
>>> print ("hello world") hello world >>>
So basically, Python 3 requires you to enclose print statements in parentheses to be more consistent with syntax of other functions. There’s no reason not to do this even when using Python 2.7 though; it accepts them either way, and using parentheses is good form and ensures your code is more readily portable to version 3.
Now, back to the first version of the furnace control script. My print statements looked like this one:
print("Furnace turned on for %d seconds. Cycle %d of %d.") % (ontime, cycle, runcycles)
See a problem? The entire print statement is not enclosed in parentheses. For python3 compatibility, I had to modify my statements like so:
print("Furnace turned on for %d seconds. Cycle %d of %d." %(ontime, cycle, runcycles))
Very simple modification, but that’s all it took to make it work. Presently the whole script is as follows:
# Import necessary modules import RPi.GPIO as GPIO import time # Set up GPIO pins GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) pins = [17,18] for pin in pins: GPIO.setup(pin,GPIO.OUT) GPIO.output(pin,1) # Set variables (change these to change behaviour as desired) runcycles = 2 ontime = 45 # minutes offtime = 20 # minutes # Convert run times from minutes to seconds for sleep function ontime *= 60 offtime *= 60 # Run furnace on cycle cycle = 0 try: while cycle < runcycles: cycle += 1 GPIO.output(17,0) print("Furnace turned on for %d seconds. Cycle %d of %d." %(ontime, cycle, runcycles)) time.sleep(ontime) GPIO.output(17,1) if cycle == runcycles: break print("Furnace paused for %s seconds. %s heat cycles remaining." %(offtime, runcycles - cycle)) time.sleep(offtime) except KeyboardInterrupt: # if Ctrl C is pressed... GPIO.output(17,1) # shut off the boiler print("Program stopped and furnace shut off.") # print a clean exit message print("Heat cycles completed.")
And now I can run the script using python2 or python3 and it makes no difference either way.