diff --git a/.drone.yml b/.drone.yml index 2d71701..d842f26 100644 --- a/.drone.yml +++ b/.drone.yml @@ -30,6 +30,7 @@ steps: - go build -o out/wifi cmd/wifi/wifi.go - go build -o out/inotify cmd/inotify/inotify.go - go build -o out/gui cmd/gui/gui.go + - go build -o out/fan cmd/fan/fan.go - cp CHANGELOG.md out/ - name: gitea-release image: plugins/gitea-release diff --git a/cmd/fan/README.md b/cmd/fan/README.md new file mode 100644 index 0000000..d82cac7 --- /dev/null +++ b/cmd/fan/README.md @@ -0,0 +1,3 @@ +# Fan + +A simple utility to control the [Argon Fan](https://www.argon40.com/argon-fan-hat-for-raspberry-pi-4-raspberry-pi-3b-and-raspberry-pi-3-b.html) speed based on CPU/GPU temperatures. diff --git a/cmd/fan/fan.go b/cmd/fan/fan.go new file mode 100644 index 0000000..3138712 --- /dev/null +++ b/cmd/fan/fan.go @@ -0,0 +1,99 @@ +package main + +import ( + "log" + "os" + "os/signal" + "syscall" + "time" + + argonFan "git.sungo.io/sungo/argon/fan" + + "git.kemonine.info/PiFrame/utils" +) + +const ( + BUS = 1 + ADDRESS = 0x1a +) + +const ( + POLL_INTERVAL = "1m" + SPEED_OFF_TEMP = 40.0 + SPEED_TWENTY_FIVE_PERCENT_TEMP = 45.0 + SPEED_FIFTY_PERCENT_TEMP = 50.0 + SPEED_SEVENTY_FIVE_PERCENT_TEMP = 55.0 + SPEED_FULL_TEMP = 57.0 +) + +func main() { + // Setup fan and bail if we can't see it + fan, err := argonFan.New(ADDRESS, BUS) + if err != nil { + log.Fatalf("Error working with fan : %s", err) + } + + // Safe exit + defer fan.SafeClose() + sigc := make(chan os.Signal, 1) + signal.Notify( + sigc, + syscall.SIGHUP, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT, + ) + go func() { + <-sigc + fan.SafeClose() + os.Exit(1) + }() + + // Control fan speed based on temps via a ticker / timeout + pollInterval, err := time.ParseDuration(POLL_INTERVAL) + if err != nil { + log.Fatalf("Error parsing interval duration : %s", err) + } + ticker := time.NewTicker(pollInterval) + go func() { + for { + select { + case <-ticker.C: + cpuTemp := utils.GetCPUTemp() + gpuTemp := utils.GetGPUTemp() + + if cpuTemp >= SPEED_FULL_TEMP || gpuTemp >= SPEED_FULL_TEMP { + fan.SetSpeed(100) + continue + } + if cpuTemp >= SPEED_SEVENTY_FIVE_PERCENT_TEMP || gpuTemp >= SPEED_SEVENTY_FIVE_PERCENT_TEMP { + fan.SetSpeed(75) + continue + } + if cpuTemp >= SPEED_FIFTY_PERCENT_TEMP || gpuTemp >= SPEED_FIFTY_PERCENT_TEMP { + fan.SetSpeed(50) + continue + } + if cpuTemp >= SPEED_TWENTY_FIVE_PERCENT_TEMP || gpuTemp >= SPEED_TWENTY_FIVE_PERCENT_TEMP { + fan.SetSpeed(25) + continue + } + if cpuTemp <= SPEED_OFF_TEMP || gpuTemp <= SPEED_OFF_TEMP { + fan.SetSpeed(0) + continue + } + // We should never get here but... + fan.SetSpeed(100) + } + } + }() + + // Infinate loop of sleeps to let ticker do it's job working with fan speed + sleepInterval, err := time.ParseDuration("5m") + if err != nil { + log.Fatalf("Error parsing sleep interval : %s", err) + } + for { + time.Sleep(sleepInterval) + } +}