{ config, lib, pkgs, ... }: let cfg = config.niri-auto-rotation; rotationScript = pkgs.writeScriptBin "niri-auto-rotate" '' #!${pkgs.bash}/bin/bash NIRI_CONFIG="$HOME/nixos/frame12/linked-dotfiles/niri/config.kdl" MONITOR="eDP-1" # Find the accelerometer device (cros-ec-accel) ACCEL_DEVICE="" for device in /sys/bus/iio/devices/iio:device*; do if [ -f "$device/name" ] && ${pkgs.gnugrep}/bin/grep -q "cros-ec-accel" "$device/name"; then ACCEL_DEVICE="$device" break fi done if [ -z "$ACCEL_DEVICE" ]; then echo "No accelerometer found!" exit 1 fi echo "Using accelerometer: $ACCEL_DEVICE" LAST_ORIENTATION="" while true; do # Read accelerometer values if [ -f "$ACCEL_DEVICE/in_accel_x_raw" ]; then X=$(${pkgs.coreutils}/bin/cat "$ACCEL_DEVICE/in_accel_x_raw") Y=$(${pkgs.coreutils}/bin/cat "$ACCEL_DEVICE/in_accel_y_raw") Z=$(${pkgs.coreutils}/bin/cat "$ACCEL_DEVICE/in_accel_z_raw") # Determine orientation based on accelerometer values # Assuming standard orientation when lid/base orientation ABS_X=''${X#-} ABS_Y=''${Y#-} ABS_Z=''${Z#-} ORIENTATION="normal" # Simple orientation detection based on which axis has highest absolute value if [ "$ABS_Z" -gt 16000 ]; then # Device is flat if [ "$Z" -lt 0 ]; then ORIENTATION="normal" else ORIENTATION="bottom-up" fi elif [ "$ABS_Y" -gt "$ABS_X" ] && [ "$ABS_Y" -gt 9000 ]; then # Y axis dominant if [ "$Y" -gt 0 ]; then ORIENTATION="normal" else ORIENTATION="bottom-up" fi elif [ "$ABS_X" -gt 9000 ]; then # X axis dominant if [ "$X" -gt 0 ]; then ORIENTATION="right-up" else ORIENTATION="left-up" fi fi # Only update if orientation changed if [ "$ORIENTATION" != "$LAST_ORIENTATION" ]; then echo "Orientation changed: $LAST_ORIENTATION -> $ORIENTATION (X=$X, Y=$Y, Z=$Z)" LAST_ORIENTATION="$ORIENTATION" case "$ORIENTATION" in "normal") ${pkgs.gnused}/bin/sed -i 's/transform ".*"/transform "normal"/' "$NIRI_CONFIG" ;; "left-up") ${pkgs.gnused}/bin/sed -i 's/transform ".*"/transform "90"/' "$NIRI_CONFIG" ;; "right-up") ${pkgs.gnused}/bin/sed -i 's/transform ".*"/transform "270"/' "$NIRI_CONFIG" ;; "bottom-up") ${pkgs.gnused}/bin/sed -i 's/transform ".*"/transform "180"/' "$NIRI_CONFIG" ;; esac fi fi ${pkgs.coreutils}/bin/sleep 0.5 done ''; in { options.niri-auto-rotation = { enable = lib.mkEnableOption "Enable automatic screen rotation for Niri using accelerometer"; user = lib.mkOption { type = lib.types.str; description = "User to run the auto-rotation service for"; }; monitor = lib.mkOption { type = lib.types.str; default = "eDP-1"; description = "Monitor name to rotate"; }; }; config = lib.mkIf cfg.enable { # Enable IIO sensor support hardware.sensor.iio.enable = true; # Add custom udev rule for Framework 12 accelerometer services.udev.extraRules = '' # Framework 12 accelerometer fix - ensure cros-ec-accel is recognized SUBSYSTEM=="iio", KERNEL=="iio:device*", ATTR{name}=="cros-ec-accel", ENV{IIO_SENSOR_PROXY_TYPE}="accel" ''; # Install required packages environment.systemPackages = with pkgs; [ iio-sensor-proxy rotationScript ]; # Create systemd user service for the rotation daemon systemd.user.services.niri-auto-rotate = { description = "Niri automatic screen rotation"; after = [ "graphical-session.target" ]; partOf = [ "graphical-session.target" ]; serviceConfig = { ExecStart = "${rotationScript}/bin/niri-auto-rotate"; Restart = "on-failure"; RestartSec = 5; }; wantedBy = [ "graphical-session.target" ]; }; }; }