I am trying to basically write a simple script that will tell the fan (plugged into pin 4 on the GPIO) to turn on at a certain temp, and if anything less, turn the fan off. I am starting with something simple just to see if I can control the fan based on temperature. Here is what I have so far:
import os
from time import sleep
import signal
import sys
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.OUT)
temp = os.popen('vcgencmd measure_temp').readline()
if temp > 65:
GPIO.output(4, True)
else:
GPIO.output(4, False)
When I run this, it either appears to run but the fan doesn't turn off even though the temp hasn't nearly reached the level I wrote, or it will tell me that the pin is already in use but it will continue anyways. Either way, the fan still runs regardless of current temp.
vgencmd returns as: temp-37.0'C
How would I remove the non-numerical characters so I am stuck with an int? When I execute it I get this:
ValueError: invalid literal for int() with base 10: "temp=37.6'C\n"
NOTE: Some of the imported modules aren't in use yet, that's why they are there.
You're very close. These two lines are problematic:
temp = os.popen('vcgencmd measure_temp').readline()
if temp > 65:
Here, temp
is a string. You need to convert temp
to an integer before trying to compare it against an integer. Assuming the line you're reading is just a decimal string corresponding to some temperature, you simply call int()
, like this:
temp = os.popen('vcgencmd measure_temp').readline()
temp = int(temp)
Update Since you posted the output you're actually trying to parse, we can use regular expressions to match the output, with the re
module. We'll also put this in a function:
def measure_temp():
raw = os.popen('vcgencmd measure_temp').readline()
m = re.match("temp=(\d+\.?\d*)'C", raw)
if not m:
raise ValueError("Unexpected temperature string: " + raw)
return float(m.group(1))
temp = measure_temp()
Note that I used a capture group around the actual temperature decimal in the string, and accessed it using m.group(1)
.
Let's put it together now. Also, when your code isn't doing what you expect, it is extremely helpful to include some "debug prints", like this:
def measure_temp():
raw = os.popen('vcgencmd measure_temp').readline()
m = re.match("temp=(\d+\.?\d*)'C", raw)
if not m:
raise ValueError("Unexpected temperature string: " + raw)
return float(m.group(1))
temp = measure_temp()
print 'Temperature from vcgencmd: {}'.format(temp)
if temp > 65:
print 'Turning on GPIO 4'
GPIO.output(4, True)
else:
print 'Turning off GPIO 4'
GPIO.output(4, False)
Once you get the basics working, there are a few other things you're going to run into:
Your script checks the temperature and toggles the GPIO once. If you want this thing to operate like a thermostat, you're going to need to keep doing these actions, using a while
loop.
If your while
loop runs very fast, and the temperature fluctuates right around your setpoint (65), you're going to find your code rapidly turning the fan on/off. It may help to add a bit of hysteresis to the system. For example, if you set your home thermostat (heating) to 70 degrees, it may come on at 69, but turn off at 71. Or it may simply not change states if it has already changed states within the last X seconds.
The simplest solution would be to sleep()
for a short period of time between checks:
while True: # Loop forever
# Read the current temperature
temp = os.popen('vcgencmd measure_temp').readline()
temp = int(temp)
print 'Temperature from vcgencmd: {}'.format(temp)
# Control the fan
if temp > 65:
print 'Turning on GPIO 4'
GPIO.output(4, True)
else:
print 'Turning off GPIO 4'
GPIO.output(4, False)
# Wait before the next iteration
time.sleep(5)