├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── fan-control.layout
├── fan-daemon.cbp
├── fan-daemon.cpp
├── fan-daemon.depend
├── fan-daemon.h
├── fan-daemon.layout
├── fan-daemon.service
├── install.sh
└── uninstall.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/Release/*
2 | /obj/Debug/*
3 | /obj/Release/*
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 William Hooper
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 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #------------------------------------------------------------------------------#
2 | # This makefile was generated by 'cbp2make' tool rev.147 #
3 | #------------------------------------------------------------------------------#
4 |
5 |
6 | WORKDIR = `pwd`
7 |
8 | CC = gcc
9 | CXX = g++
10 | AR = ar
11 | LD = g++
12 | WINDRES = windres
13 |
14 | INC =
15 | CFLAGS = -Wall -fexceptions
16 | RESINC =
17 | LIBDIR =
18 | LIB =
19 | LDFLAGS =
20 |
21 | INC_RELEASE = $(INC)
22 | CFLAGS_RELEASE = $(CFLAGS) -Os -std=c++11
23 | RESINC_RELEASE = $(RESINC)
24 | RCFLAGS_RELEASE = $(RCFLAGS)
25 | LIBDIR_RELEASE = $(LIBDIR)
26 | LIB_RELEASE = $(LIB)
27 | LDFLAGS_RELEASE = $(LDFLAGS) -s
28 | OBJDIR_RELEASE = obj/Release
29 | DEP_RELEASE =
30 | OUT_RELEASE = bin/Release/fan-daemon
31 |
32 | OBJ_RELEASE = $(OBJDIR_RELEASE)/fan-daemon.o
33 |
34 | all: Release
35 |
36 | clean: clean_release
37 |
38 | before_release:
39 | test -d bin/Release || mkdir -p bin/Release
40 | test -d $(OBJDIR_RELEASE) || mkdir -p $(OBJDIR_RELEASE)
41 |
42 | after_release:
43 |
44 | Release: before_release out_release after_release
45 |
46 | out_release: before_release $(OBJ_RELEASE) $(DEP_RELEASE)
47 | $(LD) $(LIBDIR_RELEASE) -o $(OUT_RELEASE) $(OBJ_RELEASE) $(LDFLAGS_RELEASE) $(LIB_RELEASE)
48 |
49 | $(OBJDIR_RELEASE)/fan-daemon.o: fan-daemon.cpp
50 | $(CXX) $(CFLAGS_RELEASE) $(INC_RELEASE) -c fan-daemon.cpp -o $(OBJDIR_RELEASE)/fan-daemon.o
51 |
52 | clean_release:
53 | rm -f $(OBJ_RELEASE) $(OUT_RELEASE)
54 | rm -rf bin/Release
55 | rm -rf $(OBJDIR_RELEASE)
56 |
57 | .PHONY: before_release after_release clean_release
58 |
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Jetson Nano fan control daemon
2 | Fan control daemon for the Nvidia Jetson Nano. Written in C++ to reduce the memory usage.
3 |
4 | This project is based off a similar project written in Python and found here
5 |
6 | https://github.com/Pyrestone/jetson-fan-ctl
7 |
8 | ## Requirements:
9 |
10 | ### Hardware
11 | You will need a 5V PWM fan installed for this daemon to work. The
12 | **Noctua nf-a4x20 5V PWM** or **Noctua nf-a4x10 5V PWM** fans work well.
13 | The **Noctua nf-a4x10 5V PWM** is a low profile fan and therefore not
14 | as bulky as the **Noctua nf-a4x20 5V PWM**.
15 |
16 | Additionally, it is recommend you use at a minimum a 4A power supply that supplies
17 | power via the power barrel jack. Remember to also include the power jumper to enable
18 | the external power supply.
19 |
20 | ### Software
21 | Use the standard Linux image on your Jetson Nano.
22 |
23 | ## How to install:
24 |
25 | The code is contained in a Code::Blocks project. You do not need to install
26 | Code::Blocks to build the project. To build without Code::BLocks cd into the
27 | project directory and execute
28 |
29 | make all
30 |
31 | This will build the project and place the executable in the project's
32 | ./bin/Release directory.
33 |
34 | If you have Code:Blocks you can load the project into Code::Blocks,select the
35 | Release build and build the project.
36 |
37 | Once you have built the project from the project directory exceute the install script.
38 |
39 | ./install.sh
40 |
41 | The script will install the fan-daemon as a system service which excecutes at run-time.
42 | It's a set-it-and-forget-it type thing, unless you want to modify the fan speeds.
43 |
44 | ## How to customize:
45 | In the project directory open fan_control.h in Code::Blocks or with your favorite
46 | editor and modify the following defines:
47 |
48 | #define FAN_OFF_TEMP 20
49 |
50 | #define FAN_MAX_TEMP 60
51 |
52 | #define UPDATE_INTERVAL 2
53 |
54 | FAN_OFF_TEMP
is the temperature (°C) below which the fan is turned off.
55 | FAN_MAX_TEMP
is the temperature (°C) above which the fan is at 100% speed.
56 |
57 | The daemon will interpolate linearly between these two points to determine the
58 | appropriate fan speed.
59 |
60 | UPDATE_INTERVAL
tells the daemon how often to update the fan speed (in seconds).
61 |
62 | You can use only integers in each of these fields. The temperature precision of the thermal
63 | sensors is 0.5 (°C), so don't expect the daemon to be too precise.
64 |
65 | After making changes in the daemon, compile the code and run the uninstall script to remove
66 | the old daemon. Then run the install script to install your new daemon.
67 |
68 | You can run
69 |
70 | sudo service fan-daemon restart
71 |
72 | if you wish to ensure that the changes are applied immediately.
73 |
74 | If you stop the fan control daemon with
75 |
76 | sudo service fan-daemon stop
77 |
78 | the fan is set to the fan PWM cap value.
79 |
80 | If you suspect something went wrong, please check:
81 |
82 | sudo service fan-daemon status
83 |
--------------------------------------------------------------------------------
/fan-control.layout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/fan-daemon.cbp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/fan-daemon.cpp:
--------------------------------------------------------------------------------
1 | /* Jetson Nano Fan Control Daemon
2 |
3 | * MIT License
4 | *
5 | * Copyright (c) 2019 William Hooper
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 | #include "fan-daemon.h"
26 |
27 | using namespace std;
28 |
29 | static unsigned pwmCap;
30 |
31 | /**
32 | * Exit handler. Shutoff the fan before leaving
33 | */
34 | void exit_handler(int s)
35 | {
36 | writeIntSysFs(TARGET_PWM, pwmCap);
37 | exit(1);
38 | }
39 |
40 | /**
41 | * Initialize the exit handler
42 | */
43 | void init_exit_handler()
44 | {
45 | struct sigaction sigIntHandler;
46 |
47 | sigIntHandler.sa_handler = exit_handler;
48 | sigemptyset(&sigIntHandler.sa_mask);
49 | sigIntHandler.sa_flags = 0;
50 |
51 | sigaction(SIGINT, &sigIntHandler, NULL);
52 | sigaction(SIGTERM, &sigIntHandler, NULL);
53 | }
54 |
55 |
56 | /**
57 | * Main
58 | */
59 | int main(int argc, char *argv[])
60 | {
61 | unsigned temp;
62 | unsigned pwmValue;
63 | unsigned lastPwmValue = 0;
64 |
65 | pwmCap = getPwmCap();
66 |
67 | init_exit_handler();
68 |
69 | system(JETSON_CLOCKS);
70 |
71 | while (true)
72 | {
73 | temp = readAverageTemp();
74 | pwmValue = adjustFanSpeed( temp, pwmCap);
75 | if (pwmValue != lastPwmValue)
76 | {
77 | writeIntSysFs(TARGET_PWM, pwmValue);
78 | lastPwmValue = pwmValue;
79 | }
80 | this_thread::sleep_for(chrono::milliseconds(UPDATE_INTERVAL * MICRO_SECONDS));
81 | }
82 |
83 | return 0;
84 | }
85 |
86 | /**
87 | * Read the average temperature. The function reads all thermal zones and returns the average.
88 | *
89 | */
90 | unsigned readAverageTemp()
91 | {
92 | unsigned averageTemp;
93 | glob_t globResult;
94 |
95 | averageTemp = 0;
96 | glob(THERMAL_ZONE_GLOB, GLOB_TILDE, NULL, &globResult);
97 | for(unsigned i = 0; i < globResult.gl_pathc; ++i)
98 | {
99 | averageTemp += readIntSysFs(globResult.gl_pathv[i]);
100 | }
101 |
102 | return (averageTemp / globResult.gl_pathc) / 1000;
103 | }
104 |
105 | /**
106 | * Get the PWM cap. This is maximum value that the fan PWM channel can support
107 | */
108 | unsigned getPwmCap()
109 | {
110 | return readIntSysFs(PWM_CAP);
111 | }
112 |
113 | /**
114 | * Return the adjusted PWM fan speed. Calculated from the provided temperature and the
115 | * fan PWM cap value.
116 | */
117 | unsigned adjustFanSpeed(unsigned temp, unsigned pwmCap)
118 | {
119 | unsigned speed = pwmCap * max(0, (int)(temp - FAN_OFF_TEMP)) / (FAN_MAX_TEMP - FAN_OFF_TEMP);
120 |
121 | return min((unsigned)max((unsigned)0, speed), pwmCap);
122 | }
123 |
124 | /**
125 | * Read an unsigned integer value from a sysfs path
126 | */
127 | unsigned readIntSysFs(string path)
128 | {
129 | unsigned value;
130 |
131 | ifstream infs(path);
132 | infs >> value;
133 | infs.close();
134 |
135 | return value;
136 | }
137 |
138 | /**
139 | * Write an unsigned integer value to a sysfs path
140 | */
141 | void writeIntSysFs(string path, unsigned value)
142 | {
143 | ofstream outfs(path);
144 | outfs << value;
145 | outfs.close();
146 | }
147 |
148 |
--------------------------------------------------------------------------------
/fan-daemon.depend:
--------------------------------------------------------------------------------
1 | # depslib dependency file v1.0
2 | 1561247100 source:/home/william/Projects/fan_control/main.cpp
3 |
4 |
5 |
6 |
7 |
8 | 1561255624 source:/home/william/Projects/fan_control/fan_control.cpp
9 | "fan_control.h"
10 |
11 | 1561257220 /home/william/Projects/fan_control/fan_control.h
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 1561258894 source:/home/william/Projects/fan_daemon/fan_daemon.cpp
20 | "fan_daemon.h"
21 |
22 | 1561257220 /home/william/Projects/fan_daemon/fan_daemon.h
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | 1561263666 source:/home/william/Projects/fan_daemon/fan-daemon.cpp
31 | "fan-daemon.h"
32 |
33 | 1561263559 /home/william/Projects/fan_daemon/fan-daemon.h
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | 1561266384 source:/home/william/Projects/fan-daemon/fan-daemon.cpp
46 | "fan-daemon.h"
47 |
48 | 1561266650 /home/william/Projects/fan-daemon/fan-daemon.h
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | 1561266384 source:/home/william/GitRepos/fan-daemon/fan-daemon.cpp
58 | "fan-daemon.h"
59 |
60 | 1561266650 /home/william/GitRepos/fan-daemon/fan-daemon.h
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/fan-daemon.h:
--------------------------------------------------------------------------------
1 | #ifndef FAN_CONTROL_H_INCLUDED
2 | #define FAN_CONTROL_H_INCLUDED
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | // the following three defines can be modified to change the daemon behaviour
13 | #define FAN_OFF_TEMP 45
14 | #define FAN_MAX_TEMP 60
15 | #define UPDATE_INTERVAL 2
16 | // end of modifiable code
17 |
18 |
19 | #define MICRO_SECONDS 1000
20 | #define JETSON_CLOCKS "/usr/bin/jetson_clocks"
21 | #define THERMAL_ZONE_GLOB "/sys/devices/virtual/thermal/thermal_zone*/temp"
22 | #define PWM_CAP "/sys/devices/pwm-fan/pwm_cap"
23 | #define TARGET_PWM "/sys/devices/pwm-fan/target_pwm"
24 |
25 | unsigned readAverageTemp();
26 | unsigned adjustFanSpeed(unsigned, unsigned);
27 | unsigned getPwmCap();
28 | unsigned readIntSysFs(std::string);
29 | void writeIntSysFs(std::string path, unsigned value);
30 |
31 | #endif // FAN_CONTROL_H_INCLUDED
32 |
--------------------------------------------------------------------------------
/fan-daemon.layout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/fan-daemon.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Fan control daemon
3 |
4 | [Service]
5 | Type=simple
6 | ExecStart=/usr/local/bin/fan-daemon/fan-daemon
7 | User=root
8 | StandardOutput=journal+console
9 |
10 | [Install]
11 | WantedBy=multi-user.target
12 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #Require sudo
4 | if [ $EUID != 0 ]; then
5 | sudo "$0" "$@"
6 | exit $?
7 | fi
8 |
9 | echo "setting to /usr/local/bin/fan-daemon/..."
10 | rm -rf /usr/bin/fan-daemon/ 2>/dev/null
11 | mkdir /usr/local/bin/fan-daemon
12 | cp ./bin/Release/fan-daemon /usr/local/bin/fan-daemon/
13 | echo "done"
14 |
15 | echo "adding service to /lib/systemd/system/..."
16 | cp fan-daemon.service /lib/systemd/system/
17 | chmod 644 /lib/systemd/system/fan-daemon.service
18 | echo "done"
19 |
20 | echo "starting and enabling service..."
21 | systemctl daemon-reload
22 | systemctl start fan-daemon
23 | systemctl enable fan-daemon
24 | echo "done"
25 |
26 | echo "fan-daemon installed sucessfully!"
27 |
--------------------------------------------------------------------------------
/uninstall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #Require sudo
4 | if [ $EUID != 0 ]; then
5 | sudo "$0" "$@"
6 | exit $?
7 | fi
8 |
9 | echo "removing service..."
10 | systemctl stop fan-daemon
11 | systemctl disable fan-daemon
12 | echo "done"
13 |
14 |
15 | echo "removing /usr/local/bin/fan-daemon/..."
16 | rm -r /usr/local/bin/fan-daemon
17 | rm -r /usr/bin/fan-daemon 2>/dev/null
18 | echo "done"
19 |
20 | echo "removing service from /lib/systemd/system/..."
21 | rm /lib/systemd/system/fan-daemon.service
22 | echo "done"
23 |
24 | echo "reloading services"
25 | systemctl daemon-reload
26 | echo "done"
27 |
28 | echo "fan-daemon uninstalled sucessfully!"
29 | echo ""
30 | echo "If you are find a problem, please create an issue at the repo."
31 |
--------------------------------------------------------------------------------