Powerbutton and CPU fan control for Geekworm NASPI Gemini

As this came up in a different thread with @BeepDog here is a working config for the power button and the cpu fan control script provided by Geekworm. It seems that I’m currently not using their script anymore for the service but I don’t remember the reason. For the fan control script to work the pwm-2chan dtoverlay needs to be enabled.

I’m more than happy to receive feedback on how this could be improved.

{
  pkgs,
  lib,
  ...
}: let
  xscript = pkgs.stdenv.mkDerivation {
    pname = "xscript";
    dontBuild = true;
    version = "56115c0";
    src = pkgs.fetchFromGitHub {
      owner = "geekworm-com";
      repo = "xscript";
      rev = "56115c0a45ce3797e01f1d6bb28fff655ebd985b";
      sha256 = "sha256-WkxIRIKnGhTaMmSNe/BuD4qLZhLQA4nWZ1jg30cLwXo=";
    };
    nativeBuildInputs = [pkgs.makeWrapper pkgs.gawk pkgs.libgpiod_1];
    installPhase = ''
      # echo "poweroff" >> ./xSoft.sh
      sed -i -e "s/SLEEP=4/SLEEP=0/g" ./xSoft.sh
      # sed -i -e "s/$BUTTON=1/$BUTTON=1 \&/g" ./xSoft.sh

      mkdir -p $out/bin

      cp -f ./xSoft.sh $out/bin/
      cp -f ./x-c1-fan.sh $out/bin/

      chmod +x $out/bin/*.sh

      patchShebangs $out/bin/xSoft.sh
      patchShebangs $out/bin/x-c1-fan.sh

      wrapProgram $out/bin/xSoft.sh \
        --set PATH ${lib.makeBinPath [
        pkgs.busybox
        pkgs.libgpiod_1
      ]}
      wrapProgram $out/bin/x-c1-fan.sh \
        --set PATH ${lib.makeBinPath [
        pkgs.busybox
      ]}
    '';
  };
  xPWR = pkgs.writeShellScriptBin "xPWR" ''
    PWMCHIP=0
    SHUTDOWN=4
    BOOT=17

    ${pkgs.libgpiod_1}/bin/gpioset $PWMCHIP $BOOT=1

    while [ 1 ]; do
      shutdownSignal=$(${pkgs.libgpiod_1}/bin/gpioget $PWMCHIP $SHUTDOWN)
      if [ $shutdownSignal -eq 0 ]; then
        sleep 0.2
      else
        echo "Your device is shutting down ..."
        poweroff
        exit
      fi
    done
  '';
in {
  environment.systemPackages = [xscript xPWR];
  systemd.services = {
    "x-c1-fan" = {
      serviceConfig = {
        Type = "simple";
        Restart = "always";
        ExecStart = "${xscript}/bin/x-c1-fan.sh";
      };
      wantedBy = ["multi-user.target"];
      after = ["load-pwm-2chan-overlay.target"];
    };
    "xPWR" = {
      serviceConfig = {
        Type = "simple";
        Restart = "always";
        ExecStart = "${xPWR}/bin/xPWR";
      };
      wantedBy = ["multi-user.target"];
    };
  };
}

1 Like

How did you enable the pwm-2chan overlay? I didn’t see it in the hardware repo, and I haven’t yet figured out the proper way of doing it.

I think I was coming around to the same config for that powerbutton/fan control script.

I was not sure if it was needed thats why I did not post it earlier. This works. I’m not sure if the all parts are needed as this config grew over time :slight_smile: until it worked.

{
  pkgs,
  config,
  ...
}: {
  # Load PWM hardware timers
  hardware.deviceTree = {
    enable = true;
    filter = "*-rpi-4-*.dtb";
    overlays = [
      {
        name = "pwm-2chan";
        dtsText = ''
          /dts-v1/;
          /plugin/;

          /*
          This is the 2-channel overlay - only use it if you need both channels.

          Legal pin,function combinations for each channel:
            PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0)            52,5(Alt1)
            PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)

          N.B.:
            1) Pin 18 is the only one available on all platforms, and
               it is the one used by the I2S audio interface.
               Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
            2) The onboard analogue audio output uses both PWM channels.
            3) So be careful mixing audio and PWM.
          */

          / {
          	/* compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; */
            compatible = "brcm,bcm2835";

          	fragment@0 {
          		target = <&gpio>;
          		__overlay__ {
          			pwm_pins: pwm_pins {
          				brcm,pins = <18 19>;
          				brcm,function = <2 2>; /* Alt5 */
          			};
          		};
          	};

          	fragment@1 {
          		target = <&pwm>;
          		frag1: __overlay__ {
          			pinctrl-names = "default";
          			pinctrl-0 = <&pwm_pins>;
          			status = "okay";
          		};
          	};

          	__overrides__ {
          		pin   = <&pwm_pins>,"brcm,pins:0";
          		pin2  = <&pwm_pins>,"brcm,pins:4";
          		func  = <&pwm_pins>,"brcm,function:0";
          		func2 = <&pwm_pins>,"brcm,function:4";
          		clock = <&frag1>,"assigned-clock-rates:0";
          	};
          };
        '';
      }
    ];
  };
  hardware.raspberry-pi."4".apply-overlays-dtmerge.enable = true;
  systemd.services = {
    "load-pwm-2chan-overlay" = {
      serviceConfig = {
        Type = "oneshot";
      };
      wantedBy = ["multi-user.target"];
      script = ''
        ${pkgs.libraspberrypi}/bin/dtoverlay -d ${config.boot.kernelPackages.kernel}/dtbs/overlays/ pwm-2chan || echo "already in use"
      '';
    };
  };
}
1 Like

I spent a bit of time on this, but I’ve gotta postpone it, because my pinas thing is actually the DNS server for the network, so until I do something else, that’s gotta run all the things.

I might buy a second one, so I can figure out how to get overlays working properly.

Something is really strange, and I don’t quite understand what’s going on. I think I need both the .dts and the .dtbo file. I don’t know why I need both, but it sure seems like it.

I can get the fan working if I do a few manual steps, but this host is also doing mdadm and lvm to have reliable storage, so it’s not quite cooperating well enough for me to do experiments with.

Maybe I’ll buy another one of those boards, and slap another pi onto it, and figure that part out.

I feel like I’m this close, but I’ve got too many other things I need to accomplish to go down this rabbit hole right now :frowning:

I saw on your config that you also enabled pwm0.

From what I understand it uses the same pin as the overlay above.

As I only have limited understanding of the hardware overlays I‘m unsure if this poses a problem or not.