diff --git a/flake.nix b/flake.nix index 2a36cf8..9cadacb 100644 --- a/flake.nix +++ b/flake.nix @@ -152,9 +152,9 @@ system = "x86_64-linux"; modules = nixosModules ++ [ ./machines/boxy/configuration.nix - inputs.home-manager.nixosModules.home-manager { home-manager.users.johno = import ./home/home-media-center.nix; + home-manager.users.kodi = import ./home/home-kodi.nix; home-manager.extraSpecialArgs = { inherit system; }; } ]; diff --git a/home/home-kodi.nix b/home/home-kodi.nix new file mode 100644 index 0000000..bfcfa90 --- /dev/null +++ b/home/home-kodi.nix @@ -0,0 +1,28 @@ +{ pkgs, globalInputs, system, ... }: + +{ + # Home Manager configuration for kodi user on boxy + # Focused on media center volume control via Home Assistant + + home.username = "kodi"; + home.homeDirectory = "/home/kodi"; + home.stateVersion = "24.05"; + + # Enable minimal roles for kodi user + home.roles = { + base.enable = true; + plasma-manager-kodi.enable = true; + }; + + home.packages = with pkgs; [ + kdePackages.kconfig + ]; + + targets.genericLinux.enable = true; + home.sessionVariables = {}; + home.sessionPath = []; + + imports = [ + ./roles + ]; +} diff --git a/home/roles/default.nix b/home/roles/default.nix index b99375c..0fcfd54 100644 --- a/home/roles/default.nix +++ b/home/roles/default.nix @@ -15,6 +15,7 @@ ./launchers ./media ./office + ./plasma-manager-kodi ./sync ./tmux ./emacs diff --git a/home/roles/plasma-manager-kodi/default.nix b/home/roles/plasma-manager-kodi/default.nix new file mode 100644 index 0000000..5997cd6 --- /dev/null +++ b/home/roles/plasma-manager-kodi/default.nix @@ -0,0 +1,199 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.home.roles.plasma-manager-kodi; + + # Define the volume control scripts as derivations + volumeUpScript = pkgs.writeShellScript "avr-volume-up" '' + #!/usr/bin/env bash + + # Configuration + HA_URL="https://home-assistant.johnogle.info" + ENTITY_ID="media_player.denon_avr_s970h_2" + MAX_RETRIES=3 + + # Read token from KDE Wallet and strip whitespace + TOKEN=$(${pkgs.kdePackages.kwallet}/bin/kwallet-query -r ha_avr_token kdewallet -f Passwords 2>/dev/null | tr -d '[:space:]') + + if [ -z "$TOKEN" ]; then + ${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to retrieve Home Assistant token from KDE Wallet" + exit 1 + fi + + # Send volume up command with retry logic + for i in $(seq 1 $MAX_RETRIES); do + RESPONSE=$(${pkgs.curl}/bin/curl -s -w "\n%{http_code}" -X POST \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"entity_id\": \"$ENTITY_ID\"}" \ + "$HA_URL/api/services/media_player/volume_up" 2>&1) + + HTTP_CODE=$(echo "$RESPONSE" | tail -n1) + + if [ "$HTTP_CODE" = "200" ]; then + exit 0 + fi + + # Wait before retry (except on last attempt) + if [ $i -lt $MAX_RETRIES ]; then + sleep 0.5 + fi + done + + # All retries failed + ${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to increase volume after $MAX_RETRIES attempts" + exit 1 + ''; + + volumeDownScript = pkgs.writeShellScript "avr-volume-down" '' + #!/usr/bin/env bash + + # Configuration + HA_URL="https://home-assistant.johnogle.info" + ENTITY_ID="media_player.denon_avr_s970h_2" + MAX_RETRIES=3 + + # Read token from KDE Wallet and strip whitespace + TOKEN=$(${pkgs.kdePackages.kwallet}/bin/kwallet-query -r ha_avr_token kdewallet -f Passwords 2>/dev/null | tr -d '[:space:]') + + if [ -z "$TOKEN" ]; then + ${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to retrieve Home Assistant token from KDE Wallet" + exit 1 + fi + + # Send volume down command with retry logic + for i in $(seq 1 $MAX_RETRIES); do + RESPONSE=$(${pkgs.curl}/bin/curl -s -w "\n%{http_code}" -X POST \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"entity_id\": \"$ENTITY_ID\"}" \ + "$HA_URL/api/services/media_player/volume_down" 2>&1) + + HTTP_CODE=$(echo "$RESPONSE" | tail -n1) + + if [ "$HTTP_CODE" = "200" ]; then + exit 0 + fi + + # Wait before retry (except on last attempt) + if [ $i -lt $MAX_RETRIES ]; then + sleep 0.5 + fi + done + + # All retries failed + ${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to decrease volume after $MAX_RETRIES attempts" + exit 1 + ''; + + volumeMuteScript = pkgs.writeShellScript "avr-volume-mute" '' + #!/usr/bin/env bash + + # Configuration + HA_URL="https://home-assistant.johnogle.info" + ENTITY_ID="media_player.denon_avr_s970h_2" + MAX_RETRIES=3 + + # Read token from KDE Wallet and strip whitespace + TOKEN=$(${pkgs.kdePackages.kwallet}/bin/kwallet-query -r ha_avr_token kdewallet -f Passwords 2>/dev/null | tr -d '[:space:]') + + if [ -z "$TOKEN" ]; then + ${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to retrieve Home Assistant token from KDE Wallet" + exit 1 + fi + + # Get current mute state + STATE_RESPONSE=$(${pkgs.curl}/bin/curl -s -H "Authorization: Bearer $TOKEN" \ + "$HA_URL/api/states/$ENTITY_ID") + + CURRENT_MUTE=$(echo "$STATE_RESPONSE" | ${pkgs.jq}/bin/jq -r '.attributes.is_volume_muted // false') + + # Toggle: if currently muted (true), unmute (false), and vice versa + if [ "$CURRENT_MUTE" = "true" ]; then + NEW_MUTE="false" + NOTIFY_MSG="Unmuted" + else + NEW_MUTE="true" + NOTIFY_MSG="Muted" + fi + + # Send mute toggle command with retry logic + for i in $(seq 1 $MAX_RETRIES); do + RESPONSE=$(${pkgs.curl}/bin/curl -s -w "\n%{http_code}" -X POST \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"entity_id\": \"$ENTITY_ID\", \"is_volume_muted\": $NEW_MUTE}" \ + "$HA_URL/api/services/media_player/volume_mute" 2>&1) + + HTTP_CODE=$(echo "$RESPONSE" | tail -n1) + + if [ "$HTTP_CODE" = "200" ]; then + exit 0 + fi + + # Wait before retry (except on last attempt) + if [ $i -lt $MAX_RETRIES ]; then + sleep 0.5 + fi + done + + # All retries failed + ${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to toggle mute after $MAX_RETRIES attempts" + exit 1 + ''; +in +{ + options.home.roles.plasma-manager-kodi = { + enable = mkEnableOption "KDE Plasma volume control for kodi user via Home Assistant"; + }; + + config = mkIf cfg.enable { + programs.plasma = { + enable = true; + overrideConfig = true; + + # Disable default kmix volume shortcuts to prevent conflicts + shortcuts.kmix = { + "increase_volume" = "none"; + "decrease_volume" = "none"; + "mute" = "none"; + }; + + # Define custom volume control commands with key bindings + hotkeys.commands = { + "volume-up-avr" = { + name = "Volume Up AVR"; + key = "Volume Up"; + command = toString volumeUpScript; + }; + + "volume-down-avr" = { + name = "Volume Down AVR"; + key = "Volume Down"; + command = toString volumeDownScript; + }; + + "volume-mute-avr" = { + name = "Mute Toggle AVR"; + key = "Volume Mute"; + command = toString volumeMuteScript; + }; + }; + + # KDE Settings customization + configFile = { + # Session restore settings + "ksmserverrc"."General"."loginMode" = "emptySession"; + + # Screen locking settings + "kscreenlockerrc"."Daemon"."Autolock" = false; + "kscreenlockerrc"."Daemon"."LockOnResume" = false; + + # Theme settings + "kdeglobals"."KDE"."LookAndFeelPackage" = "org.kde.breezedark.desktop"; + }; + }; + }; +} diff --git a/machines/boxy/configuration.nix b/machines/boxy/configuration.nix index 9ead5e6..1a2425b 100644 --- a/machines/boxy/configuration.nix +++ b/machines/boxy/configuration.nix @@ -26,11 +26,20 @@ with lib; enable = true; autologin = true; wayland = true; - jellyfinScaleFactor = 2.5; + jellyfinScaleFactor = 1.0; }; + nfs-mounts.enable = true; users.enable = true; }; + # Enable KDE Wallet PAM integration for auto-unlock + security.pam.services.sddm = { + kwallet = { + enable = true; + package = pkgs.kdePackages.kwallet-pam; + }; + }; + # Use the systemd-boot EFI boot loader. boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true;