nixos/home-assistant: add themes support

This commit is contained in:
Julian Pinzer 2026-02-24 22:02:50 -08:00 committed by Jamie Magee
commit 63b4d66ff5
3 changed files with 72 additions and 2 deletions

View file

@ -71,7 +71,7 @@ let
# Filter null values from the configuration, so that we can still advertise
# optional options in the config attribute.
filteredConfig = converge (filterAttrsRecursive (_: v: !elem v [ null ])) (
recursiveUpdate customLovelaceModulesResources (cfg.config or { })
recursiveUpdate (customLovelaceModulesResources // themesConfig) (cfg.config or { })
);
configFile = renderYAMLFile "configuration.yaml" filteredConfig;
@ -143,7 +143,7 @@ let
paths = cfg.customLovelaceModules;
};
# Create parts of the lovelace config that reference lovelave modules as resources
# Create parts of the lovelace config that reference lovelace modules as resources
customLovelaceModulesResources = {
lovelace.resources = map (card: {
url = "/local/nixos-lovelace-modules/${card.entrypoint or (card.pname + ".js")}?${card.version}";
@ -151,6 +151,21 @@ let
}) cfg.customLovelaceModules;
};
# Create a directory that holds all lovelace themes
themesDir = pkgs.buildEnv {
name = "home-assistant-themes";
paths = cfg.themes;
};
# Auto-inject frontend.themes include directive when themes are used.
themesConfig =
if cfg.themes != [ ] then
{
frontend.themes = "!include_dir_merge_named ${themesDir}/themes";
}
else
{ };
componentsUsingBluetooth = [
# Components that require the AF_BLUETOOTH address family
"august"
@ -444,6 +459,33 @@ in
'';
};
themes = mkOption {
type = types.listOf (
types.addCheck types.package (p: p.isHomeAssistantTheme or false)
// {
name = "home-assistant-theme";
description = "package that is a Home Assistant theme";
}
);
default = [ ];
example = literalExpression ''
with pkgs.home-assistant-themes; [
material-you-theme
];
'';
description = ''
List of themes to load.
Available themes can be found below `pkgs.home-assistant-themes`.
::: {.note}
When `themes` is set, the module takes authoritative control
over the `frontend.themes` setting in
{option}`services.home-assistant.config`.
:::
'';
};
config = mkOption {
type = types.nullOr (
types.submodule {
@ -797,6 +839,10 @@ in
assertion = !(cfg.lovelaceConfig != null && cfg.lovelaceConfigFile != null);
message = "Only one of `lovelaceConfig` or `lovelaceConfigFile` can be configured at the same time.";
}
{
assertion = cfg.themes != [ ] -> !(hasAttrByPath [ "frontend" "themes" ] (cfg.config or { }));
message = "`services.home-assistant.themes` and `services.home-assistant.config.frontend.themes` cannot both be set. When `themes` is non-empty the module sets `frontend.themes` authoritatively.";
}
];
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.config.http.server_port ];
@ -880,6 +926,7 @@ in
ln -fns "''${paths[@]}" "${cfg.configDir}/custom_components/"
done
'';
removeBlueprints = ''
# remove blueprints symlinked in from below the /nix/store
readarray -d "" blueprints < <(find "${cfg.configDir}/blueprints" -maxdepth 2 -type l -print0)

View file

@ -71,6 +71,11 @@ in
mini-graph-card
];
# test loading themes
themes = with pkgs.home-assistant-themes; [
material-you-theme
];
config = {
homeassistant = {
name = "Home";
@ -250,6 +255,11 @@ in
hass.succeed("grep -q 'mini-graph-card-bundle.js' '${configDir}/configuration.yaml'")
hass.succeed("curl --fail http://localhost:8123/local/nixos-lovelace-modules/mini-graph-card-bundle.js")
with subtest("Check that themes are referenced and installed"):
hass.succeed("grep -q '!include_dir_merge_named.*themes' '${configDir}/configuration.yaml'")
themes_dir = hass.succeed("sed -n 's/.*!include_dir_merge_named \\(.*\\)/\\1/p' '${configDir}/configuration.yaml'").strip()
hass.succeed(f"test -f {themes_dir}/material_you.yaml")
with subtest("Check that optional dependencies are in the PYTHONPATH"):
env = get_unit_property("Environment")
python_path = env.split("PYTHONPATH=")[1].split()[0]

View file

@ -0,0 +1,13 @@
# Packaging guidelines
## isHomeAssistantTheme
The nixos module checks for `passthru.isHomeAssistantTheme` on every
package passed to `services.home-assistant.themes`, and rejects packages
that don't have it set. Mark a theme package like this:
```nix
{ passthru.isHomeAssistantTheme = true; }
```
Themes are expected to install their `.yaml` files into `$out/themes/`.