Skip to content
Open
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
27a1ea0
Replace shell script and parse for temp with reading from sys
Bengreen Jan 26, 2020
25cd828
Read the core temperature from the file
michael-sulyak Jun 13, 2020
5c39db6
Update fancontrol.py
Kukers86PL Aug 22, 2020
833880b
Update fancontrol.py
Kukers86PL Aug 24, 2020
b87e648
Update fancontrol.py
Kukers86PL Aug 25, 2020
a51a851
Merge pull request #2 from Bengreen/simplify-temp-fetch
josephtyler Oct 26, 2020
d91a04f
Merge branch 'master' into master
josephtyler Oct 27, 2020
ca63427
Merge pull request #5 from expert-m/master
josephtyler Oct 27, 2020
8c32a10
Update fancontrol.py
Kukers86PL Jul 28, 2021
3515455
Update fancontrol.py
Kukers86PL Jul 28, 2021
be8b073
Update fancontrol.py
Kukers86PL Jul 28, 2021
ff592b1
Update fancontrol.py
Kukers86PL Jul 28, 2021
f65c964
Update fancontrol.py
Kukers86PL Jul 28, 2021
402bd64
Update fancontrol.py
Kukers86PL Jul 28, 2021
9115d2f
Get temp method update
Kukers86PL Sep 2, 2021
b3d1beb
Update fancontrol.py
Kukers86PL Aug 22, 2020
dd8b1eb
Update fancontrol.py
Kukers86PL Aug 24, 2020
6021499
Update fancontrol.py
Kukers86PL Aug 25, 2020
e3fe992
Update fancontrol.py
Kukers86PL Jul 28, 2021
30a036f
Update fancontrol.py
Kukers86PL Jul 28, 2021
43654fd
Update fancontrol.py
Kukers86PL Jul 28, 2021
2f35248
Update fancontrol.py
Kukers86PL Jul 28, 2021
26d4f50
Update fancontrol.py
Kukers86PL Jul 28, 2021
7ee78ec
Update fancontrol.py
Kukers86PL Jul 28, 2021
1dd6574
Update fancontrol.py
Kukers86PL Jan 9, 2022
154ef05
Merge branch 'master' of https://github.com/kukers86/pi-fan-controller
Kukers86PL Jan 9, 2022
c675f6c
Update fancontrol.py
Kukers86PL Jan 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 56 additions & 33 deletions fancontrol.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,55 +1,78 @@
#!/usr/bin/env python3

import subprocess
import time

from gpiozero import OutputDevice


ON_THRESHOLD = 65 # (degrees Celsius) Fan kicks on at this temperature.
OFF_THRESHOLD = 55 # (degress Celsius) Fan shuts off at this temperature.
SLEEP_INTERVAL = 5 # (seconds) How often we check the core temperature.
GPIO_PIN = 17 # Which GPIO pin you're using to control the fan.

MAX_THRESHOLD = 60.0 # (degrees Celsius) Fan kicks on at full speed at this temperature.
MIN_THRESHOLD = 50.0 # (degress Celsius) Fan kicks on at minimum speed at this temperature.
SLEEP_INTERVAL = 1.0 # (miliseconds) How long one tick last
GPIO_PIN = 17 # Which GPIO pin you're using to control the fan.
MIN_TICKS = 100 # Number of min ticks in cycle
MAX_TICKS = 1000 # Number of max ticks in cycle
FAN_ON = 1
FAN_OFF = 0

def get_temp():
"""Get the core temperature.

Run a shell script to get the core temp and parse the output.

Raises:
RuntimeError: if response cannot be parsed.

Read file from /sys to get CPU temp in temp in C *1000
Returns:
float: The core temperature in degrees Celsius.
int: The core temperature in thousanths of degrees Celsius.
"""
output = subprocess.run(['vcgencmd', 'measure_temp'], capture_output=True)
temp_str = output.stdout.decode()
try:
return float(temp_str.split('=')[1].split('\'')[0])
except (IndexError, ValueError):
raise RuntimeError('Could not parse temperature output.')
with open('/sys/class/thermal/thermal_zone0/temp') as f:
temp_str = f.read()

try:
return int(temp_str) / 1000
except (IndexError, ValueError,) as e:
raise RuntimeError('Could not parse temperature output.') from e

def normalize_temp(temp):
temp = ((float(temp) - MIN_THRESHOLD) / (MAX_THRESHOLD - MIN_THRESHOLD))
if temp < 0.0:
temp = 0.0
if temp > 1.0:
temp = 1.0
return float(temp)

def count_fire_tick(temp):
temp = int((MAX_TICKS / MIN_TICKS) - (MAX_TICKS / MIN_TICKS) * float(temp))
if temp <= 0:
temp = 1
return int(temp)

def fan_command(command, fan):
if command == FAN_ON and not fan.value:
fan.on()
if command == FAN_OFF and fan.value:
fan.off()

def run_cycle(fire_tick, fan):
i = 0
while i < MAX_TICKS:
i += 1
if (i % fire_tick) == 0:
fan_command(FAN_ON, fan)
time.sleep(SLEEP_INTERVAL / 1000.0)
if (i % fire_tick) != 0:
fan_command(FAN_OFF, fan)

if __name__ == '__main__':
# Validate the on and off thresholds
if OFF_THRESHOLD >= ON_THRESHOLD:
raise RuntimeError('OFF_THRESHOLD must be less than ON_THRESHOLD')
# Validate the min and max thresholds
if MIN_THRESHOLD >= MAX_THRESHOLD:
raise RuntimeError('MIN_THRESHOLD must be less than MAX_THRESHOLD')

# Validate the min and max ticks
if MIN_TICKS >= MAX_TICKS:
raise RuntimeError('MIN_TICKS must be less than MAX_TICKS')

fan = OutputDevice(GPIO_PIN)

while True:
temp = get_temp()

# Start the fan if the temperature has reached the limit and the fan
# isn't already running.
# NOTE: `fan.value` returns 1 for "on" and 0 for "off"
if temp > ON_THRESHOLD and not fan.value:
fan.on()
temp = normalize_temp(temp)

# Stop the fan if the fan is running and the temperature has dropped
# to 10 degrees below the limit.
elif fan.value and temp < OFF_THRESHOLD:
fan.off()
temp = count_fire_tick(temp)

time.sleep(SLEEP_INTERVAL)
run_cycle(temp, fan)