diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix
index 86033d02bf3f2..27a3a680b2575 100644
--- a/nixos/modules/services/misc/home-assistant.nix
+++ b/nixos/modules/services/misc/home-assistant.nix
@@ -5,10 +5,12 @@ with lib;
let
cfg = config.services.home-assistant;
- # cfg.config != null can be assumed here
+ # Combined config
+ hassConfig = recursiveUpdate
+ (optionalAttrs cfg.applyDefaultConfig defaultConfig)
+ (optionalAttrs (cfg.config != null) cfg.config);
configJSON = pkgs.writeText "configuration.json"
- (builtins.toJSON (if cfg.applyDefaultConfig then
- (recursiveUpdate defaultConfig cfg.config) else cfg.config));
+ (builtins.toJSON hassConfig);
configFile = pkgs.runCommand "configuration.yaml" { preferLocalBuild = true; } ''
${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out
# Hack to support secrets, that are encoded as custom yaml objects,
@@ -40,11 +42,11 @@ let
# platform = "mqtt";
# ...
# } ];
- useComponentPlatform = component: elem component (usedPlatforms cfg.config);
+ useComponentPlatform = component: elem component (usedPlatforms hassConfig);
# Returns whether component is used in config
useComponent = component:
- hasAttrByPath (splitString "." component) cfg.config
+ hasAttrByPath (splitString "." component) hassConfig
|| useComponentPlatform component;
# List of components used in config
@@ -56,8 +58,10 @@ let
# If you are changing this, please update the description in applyDefaultConfig
defaultConfig = {
- homeassistant.time_zone = config.time.timeZone;
+ frontend = {};
http.server_port = cfg.port;
+ } // optionalAttrs (config.time.timeZone != null) {
+ homeassistant.time_zone = config.time.timeZone;
} // optionalAttrs (cfg.lovelaceConfig != null) {
lovelace.mode = "yaml";
};
@@ -87,10 +91,9 @@ in {
Setting this option enables a few configuration options for HA based on NixOS configuration (such as time zone) to avoid having to manually specify configuration we already have.
- Currently one side effect of enabling this is that the http component will be enabled.
+ Currently one side effect of enabling this is that the http and frontend components will be enabled.
- This only takes effect if config != null in order to ensure that a manually managed configuration.yaml is not overwritten.
'';
};
@@ -225,7 +228,7 @@ in {
systemd.services.home-assistant = {
description = "Home Assistant";
after = [ "network.target" ];
- preStart = optionalString (cfg.config != null) (if cfg.configWritable then ''
+ preStart = (if cfg.configWritable then ''
cp --no-preserve=mode ${configFile} "${cfg.configDir}/configuration.yaml"
'' else ''
rm -f "${cfg.configDir}/configuration.yaml"
diff --git a/nixos/tests/home-assistant-config.nix b/nixos/tests/home-assistant-config.nix
new file mode 100644
index 0000000000000..752066c3f9ffa
--- /dev/null
+++ b/nixos/tests/home-assistant-config.nix
@@ -0,0 +1,65 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+
+let
+ configDir = "/var/lib/hass";
+ configFile = "${configDir}/configuration.yaml";
+ port = 4000;
+
+ mkHass = { machineAttrs ? {}, hassAttrs ? {} }:
+ { pkgs, ... }:
+ {
+ services.home-assistant = {
+ inherit configDir port;
+ enable = true;
+ } // hassAttrs;
+ } // machineAttrs;
+in {
+ name = "home-assistant-config";
+
+ nodes = {
+ hassMinimal = mkHass {};
+
+ hassTimeZone = mkHass {
+ machineAttrs = { time.timeZone = "UTC"; };
+ };
+
+ hassNoDefault = mkHass {
+ hassAttrs = { applyDefaultConfig = false; };
+ };
+ };
+
+ testScript = let
+ portStr = toString port;
+ in ''
+ start_all()
+
+
+ def check_availability(hass):
+ hass.wait_for_unit("home-assistant.service")
+ with subtest("Check that Home Assistant can be reached via port ${portStr}"):
+ hass.wait_for_open_port(${portStr})
+ hass.succeed("curl --fail http://localhost:${portStr}")
+
+
+ check_availability(hassMinimal)
+ with subtest("Check that port is set"):
+ config = hassMinimal.succeed("cat ${configFile}")
+ assert "server_port: ${portStr}" in config
+
+ check_availability(hassTimeZone)
+ with subtest("Check that default_config, port and time_zone are set"):
+ config = hassTimeZone.succeed("cat ${configFile}")
+ assert "server_port: ${portStr}" in config
+ assert "time_zone: UTC" in config
+
+ hassNoDefault.wait_for_unit("home-assistant.service")
+
+ with subtest("Check that server port is not set"):
+ config = hassNoDefault.succeed("cat ${configFile}")
+ assert "server_port: ${portStr}" not in config
+
+ # It cannot be reached because defaults (i.e. http.server_port, frontend) are not set
+ with subtest("Check that Home Assistant cannot be reached via port ${portStr}"):
+ hassNoDefault.wait_for_closed_port(${portStr})
+ '';
+})