├── .gitignore ├── LICENSE ├── README.md ├── install-systemd-file.sh ├── pi-fan-tuner.service ├── pi_fan_tuner.py ├── resources ├── circuit_diagram.jpg ├── gpio_readall_screenshot.jpg └── s8050.jpg └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | .idea/ 91 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Ji Qu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PIFanTuner 2 | RaspberryPI CPU fan tuner with a s8050 triode. 3 | 4 | This project enables a daemon which manage a CPU fan for you, it will start 5 | after system bootstrapping automatically.It enables CPU fan while its temperature 6 | is more than 45°(or defined by you), else the fan will be turned off. 7 | 8 | You can also view your cpu temperature within this project or turn on/off 9 | a given GPIO port by simple commandline tool. 10 | 11 | # How to 12 | 13 | ## Requires 14 | Hardware 15 | 16 | + A Fan that works under 5v Voltage 17 | + A NPN triode(such as s8050) 18 | 19 | Software 20 | 21 | + Python 2.6+ 22 | + Raspbian(optional) 23 | 24 | ## Hardware Setup 25 | At first , follow the diagram below and connect your triode and fan together. 26 | 27 | Your triode may be like this one: 28 | 29 | ![s8050](resources/s8050.jpg) 30 | 31 | The circuit diagram is like this one: 32 | 33 | ![circuit-diagram](resources/circuit_diagram.jpg) 34 | 35 | 36 | About Raspberry Pi PIN number 37 | 38 | Use `gpio readall` to get map like following image. 39 | 40 | ![screenshot](resources/gpio_readall_screenshot.jpg) 41 | 42 | 43 | ## Software Setup 44 | 45 | 46 | ### General 47 | Enter console of your Raspberry Pi then start with 48 | 49 | ``` 50 | git clone https://github.com/winkidney/PIFanTuner.git 51 | ``` 52 | 53 | Or just download the zip file zipped by Github. 54 | 55 | Then enter the project directory: 56 | 57 | ``` 58 | sudo python setup.py install 59 | ``` 60 | 61 | Now use following command to run fan-control daemon: 62 | 63 | ``` 64 | ➜ ~ pi-fan-tuner fan simple --debug 65 | DEBUG:root:Temperature 45.084 CPU fan on. 66 | ``` 67 | 68 | ### Raspbian 69 | 70 | With raspbian or any system works well with systemd, you can use systemd 71 | service script to make `pi-fan-tuner` a daemon which automatically manage 72 | your fan. 73 | 74 | After installation of the python package, you could run 75 | ``` 76 | ./install-systemd-file.sh 77 | ``` 78 | 79 | to setup the systemd script for `pi-fan-tuner`. 80 | 81 | 82 | ## Advanced 83 | 84 | Monitoring CPU temperature 85 | ``` 86 | pi-fan-tuner cpu-show --loop 87 | ``` 88 | 89 | For other usage, please run: 90 | 91 | ``` 92 | pi-fan-tuner --help 93 | ``` -------------------------------------------------------------------------------- /install-systemd-file.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | sudo cp pi-fan-tuner.service /lib/systemd/system/pi-fan-tuner.service 3 | sudo systemctl daemon-reload 4 | sudo systemctl enable pi-fan-tuner 5 | sudo systemctl start pi-fan-tuner -------------------------------------------------------------------------------- /pi-fan-tuner.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=PI Fan Tunner Daemon 3 | Wants=udev.service 4 | After=udev.service 5 | 6 | [Service] 7 | ExecStart=/usr/local/bin/pi-fan-tuner fan simple 8 | WorkingDirectory=/tmp 9 | Restart=on-failure 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | 14 | -------------------------------------------------------------------------------- /pi_fan_tuner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | # coding:utf-8 3 | import logging 4 | from time import sleep 5 | 6 | from RPi import GPIO 7 | 8 | from cmdtree import INT 9 | from cmdtree import command 10 | from cmdtree import entry 11 | from cmdtree import group 12 | from cmdtree import option 13 | 14 | 15 | GPIO_CONTROL_PORT = 12 16 | FAN_ON_TEMPERATURE = 45 17 | 18 | 19 | def get_cpu_temp(): 20 | with open("/sys/class/thermal/thermal_zone0/temp", 'r') as f: 21 | temp = float(f.read()) / 1000 22 | return temp 23 | 24 | 25 | def init(): 26 | GPIO.setmode(GPIO.BOARD) 27 | 28 | 29 | def set_debug(): 30 | logging.basicConfig(level=logging.DEBUG) 31 | 32 | 33 | @group(name="port", help="Turn a pin port to `IN` or `OUT`") 34 | def port_manage(): 35 | pass 36 | 37 | 38 | @option("port", help="Port on GPIO Physical Port", type=INT, default=GPIO_CONTROL_PORT) 39 | @port_manage.command("turn-out", help="Turn a port into `OUT` mode") 40 | def turn_port_out(port): 41 | GPIO.setup(port, GPIO.OUT) 42 | GPIO.output(port, 1) 43 | return True 44 | 45 | 46 | @option("port", help="Port number of GPIO Physical Port", type=INT, default=GPIO_CONTROL_PORT) 47 | @port_manage.command("turn-in", help="Turn a port into `IN` mode") 48 | def turn_port_in(port): 49 | GPIO.setup(port, GPIO.IN) 50 | return False 51 | 52 | 53 | @option("loop", help="loop until user interrupting execution.", is_flag=True) 54 | @command("cpu-show") 55 | def show_cpu_temperature(loop): 56 | 57 | def show_temperature(): 58 | print("Cpu Temperature is: {0}".format(get_cpu_temp())) 59 | 60 | if loop: 61 | while True: 62 | show_temperature() 63 | sleep(1) 64 | else: 65 | show_temperature() 66 | 67 | 68 | @option( 69 | "on-t", 70 | help="Temperature which triggers the fan on.", 71 | type=INT, 72 | default=FAN_ON_TEMPERATURE, 73 | ) 74 | @option( 75 | "port", 76 | help="Port number of GPIO Physical Port", 77 | type=INT, 78 | default=GPIO_CONTROL_PORT, 79 | ) 80 | @group(name="fan", help="Auto tune the cpu fan in `simple` or `auto` mode.") 81 | def auto_fan(): 82 | pass 83 | 84 | 85 | @auto_fan.command("on", help="Turn one the fan.") 86 | def on_fan(port, **kwargs): 87 | turn_port_out(port) 88 | 89 | 90 | @auto_fan.command("off", help="Turn off the fan.") 91 | def off_fan(port, **kwargs): 92 | turn_port_in(port) 93 | 94 | 95 | @option("debug", is_flag=True, default=False) 96 | @auto_fan.command("simple", help="Simply turn on or off the fan in given temperature range.") 97 | def simple_on_of(debug, port, on_t): 98 | if debug: 99 | set_debug() 100 | 101 | fan_on = turn_port_in(port) 102 | 103 | try: 104 | while True: 105 | temperature = get_cpu_temp() 106 | if temperature >= on_t: 107 | if not fan_on: 108 | logging.debug("Temperature {0} CPU fan on.".format(temperature)) 109 | fan_on = turn_port_out(port) 110 | else: 111 | if fan_on: 112 | logging.debug("Temperature {0} CPU fan off.".format(temperature)) 113 | fan_on = turn_port_in(port) 114 | sleep(10) 115 | except Exception: 116 | logging.exception("Error occurs while tune fan status:") 117 | GPIO.cleanup() 118 | 119 | 120 | def main(): 121 | init() 122 | entry() 123 | 124 | 125 | if __name__ == '__main__': 126 | main() 127 | -------------------------------------------------------------------------------- /resources/circuit_diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winkidney/PIFanTuner/b39d5ccfd1a5483c4b3ee6492d9db90cbd631d98/resources/circuit_diagram.jpg -------------------------------------------------------------------------------- /resources/gpio_readall_screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winkidney/PIFanTuner/b39d5ccfd1a5483c4b3ee6492d9db90cbd631d98/resources/gpio_readall_screenshot.jpg -------------------------------------------------------------------------------- /resources/s8050.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winkidney/PIFanTuner/b39d5ccfd1a5483c4b3ee6492d9db90cbd631d98/resources/s8050.jpg -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | install_requires = [ 4 | "cmdtree>=0.0.3", 5 | "RPi.GPIO>=0.6.0", 6 | ] 7 | 8 | entry_points = { 9 | 'console_scripts': ['pi-fan-tuner=pi_fan_tuner:main'], 10 | } 11 | 12 | setup( 13 | name='PIFanTuner', 14 | version='0.0.1', 15 | py_modules=["pi_fan_tuner", ], 16 | install_requires=install_requires, 17 | entry_points=entry_points, 18 | url='https://github.com/winkidney/PIFanTuner', 19 | license='MIT', 20 | author='winkidney', 21 | author_email='winkidney@gmail.com', 22 | description='RaspberryPI CPU fan tuner with a s8050 Triode', 23 | ) 24 | --------------------------------------------------------------------------------