nixos/home-assistant: convert to rfc42 style settings
After this change users with non-declarative configs need to set `services.home-assistant.config` to an `null`, or their `configuration.yaml` will be overwritten. The reason for this is that with rfc42 style defaults the config attribute set will never be empty by default.
This commit is contained in:
@@ -269,6 +269,23 @@
|
|||||||
<literal>(ghc.withPackages.override { useLLVM = true; }) (p: [])</literal>.
|
<literal>(ghc.withPackages.override { useLLVM = true; }) (p: [])</literal>.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <literal>home-assistant</literal> module now requires
|
||||||
|
users that don’t want their configuration to be managed
|
||||||
|
declaratively to set
|
||||||
|
<literal>services.home-assistant.config = null;</literal>.
|
||||||
|
This is required due to the way default settings are handled
|
||||||
|
with the new settings style.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Additionally the default list of
|
||||||
|
<literal>extraComponents</literal> now includes the minimal
|
||||||
|
dependencies to successfully complete the
|
||||||
|
<link xlink:href="https://www.home-assistant.io/getting-started/onboarding/">onboarding</link>
|
||||||
|
procedure.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<literal>pkgs.emacsPackages.orgPackages</literal> is removed
|
<literal>pkgs.emacsPackages.orgPackages</literal> is removed
|
||||||
|
|||||||
@@ -91,6 +91,15 @@ In addition to numerous new and upgraded packages, this release has the followin
|
|||||||
`useLLVM`. So instead of `(ghc.withPackages (p: [])).override { withLLVM = true; }`,
|
`useLLVM`. So instead of `(ghc.withPackages (p: [])).override { withLLVM = true; }`,
|
||||||
one needs to use `(ghc.withPackages.override { useLLVM = true; }) (p: [])`.
|
one needs to use `(ghc.withPackages.override { useLLVM = true; }) (p: [])`.
|
||||||
|
|
||||||
|
- The `home-assistant` module now requires users that don't want their
|
||||||
|
configuration to be managed declaratively to set
|
||||||
|
`services.home-assistant.config = null;`. This is required
|
||||||
|
due to the way default settings are handled with the new settings style.
|
||||||
|
|
||||||
|
Additionally the default list of `extraComponents` now includes the minimal
|
||||||
|
dependencies to successfully complete the [onboarding](https://www.home-assistant.io/getting-started/onboarding/)
|
||||||
|
procedure.
|
||||||
|
|
||||||
- `pkgs.emacsPackages.orgPackages` is removed because org elpa is deprecated.
|
- `pkgs.emacsPackages.orgPackages` is removed because org elpa is deprecated.
|
||||||
The packages in the top level of `pkgs.emacsPackages`, such as org and
|
The packages in the top level of `pkgs.emacsPackages`, such as org and
|
||||||
org-contrib, refer to the ones in `pkgs.emacsPackages.elpaPackages` and
|
org-contrib, refer to the ones in `pkgs.emacsPackages.elpaPackages` and
|
||||||
|
|||||||
@@ -4,35 +4,27 @@ with lib;
|
|||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.home-assistant;
|
cfg = config.services.home-assistant;
|
||||||
|
format = pkgs.formats.yaml {};
|
||||||
|
|
||||||
# cfg.config != null can be assumed here
|
# Render config attribute sets to YAML
|
||||||
configJSON = pkgs.writeText "configuration.json"
|
# Values that are null will be filtered from the output, so this is one way to have optional
|
||||||
(builtins.toJSON (if cfg.applyDefaultConfig then
|
# options shown in settings.
|
||||||
(recursiveUpdate defaultConfig cfg.config) else cfg.config));
|
# We post-process the result to add support for YAML functions, like secrets or includes, see e.g.
|
||||||
|
# https://www.home-assistant.io/docs/configuration/secrets/
|
||||||
|
filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! elem v [ null ])) cfg.config or {};
|
||||||
configFile = pkgs.runCommand "configuration.yaml" { preferLocalBuild = true; } ''
|
configFile = pkgs.runCommand "configuration.yaml" { preferLocalBuild = true; } ''
|
||||||
${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out
|
cp ${format.generate "configuration.yaml" filteredConfig} $out
|
||||||
# Hack to support custom yaml objects,
|
|
||||||
# i.e. secrets: https://www.home-assistant.io/docs/configuration/secrets/
|
|
||||||
sed -i -e "s/'\!\([a-z_]\+\) \(.*\)'/\!\1 \2/;s/^\!\!/\!/;" $out
|
sed -i -e "s/'\!\([a-z_]\+\) \(.*\)'/\!\1 \2/;s/^\!\!/\!/;" $out
|
||||||
'';
|
'';
|
||||||
|
lovelaceConfig = cfg.lovelaceConfig or {};
|
||||||
|
lovelaceConfigFile = format.generate "ui-lovelace.yaml" lovelaceConfig;
|
||||||
|
|
||||||
lovelaceConfigJSON = pkgs.writeText "ui-lovelace.json"
|
# Components advertised by the home-assistant package
|
||||||
(builtins.toJSON cfg.lovelaceConfig);
|
|
||||||
lovelaceConfigFile = pkgs.runCommand "ui-lovelace.yaml" { preferLocalBuild = true; } ''
|
|
||||||
${pkgs.remarshal}/bin/json2yaml -i ${lovelaceConfigJSON} -o $out
|
|
||||||
'';
|
|
||||||
|
|
||||||
availableComponents = cfg.package.availableComponents;
|
availableComponents = cfg.package.availableComponents;
|
||||||
|
|
||||||
|
# Components that were added by overriding the package
|
||||||
explicitComponents = cfg.package.extraComponents;
|
explicitComponents = cfg.package.extraComponents;
|
||||||
|
useExplicitComponent = component: elem component explicitComponents;
|
||||||
usedPlatforms = config:
|
|
||||||
if isAttrs config then
|
|
||||||
optional (config ? platform) config.platform
|
|
||||||
++ concatMap usedPlatforms (attrValues config)
|
|
||||||
else if isList config then
|
|
||||||
concatMap usedPlatforms config
|
|
||||||
else [ ];
|
|
||||||
|
|
||||||
# Given a component "platform", looks up whether it is used in the config
|
# Given a component "platform", looks up whether it is used in the config
|
||||||
# as `platform = "platform";`.
|
# as `platform = "platform";`.
|
||||||
@@ -42,33 +34,42 @@ let
|
|||||||
# platform = "mqtt";
|
# platform = "mqtt";
|
||||||
# ...
|
# ...
|
||||||
# } ];
|
# } ];
|
||||||
|
usedPlatforms = config:
|
||||||
|
if isAttrs config then
|
||||||
|
optional (config ? platform) config.platform
|
||||||
|
++ concatMap usedPlatforms (attrValues config)
|
||||||
|
else if isList config then
|
||||||
|
concatMap usedPlatforms config
|
||||||
|
else [ ];
|
||||||
|
|
||||||
useComponentPlatform = component: elem component (usedPlatforms cfg.config);
|
useComponentPlatform = component: elem component (usedPlatforms cfg.config);
|
||||||
|
|
||||||
useExplicitComponent = component: elem component explicitComponents;
|
# Returns whether component is used in config, explicitly passed into package or
|
||||||
|
# configured in the module.
|
||||||
# Returns whether component is used in config or explicitly passed into package
|
|
||||||
useComponent = component:
|
useComponent = component:
|
||||||
hasAttrByPath (splitString "." component) cfg.config
|
hasAttrByPath (splitString "." component) cfg.config
|
||||||
|| useComponentPlatform component
|
|| useComponentPlatform component
|
||||||
|| useExplicitComponent component;
|
|| useExplicitComponent component;
|
||||||
|
|
||||||
# List of components used in config
|
# Final list of components passed into the package to include required dependencies
|
||||||
extraComponents = filter useComponent availableComponents;
|
extraComponents = filter useComponent availableComponents;
|
||||||
|
|
||||||
package = if (cfg.autoExtraComponents && cfg.config != null)
|
package = (cfg.package.override {
|
||||||
then (cfg.package.override { inherit extraComponents; })
|
inherit extraComponents;
|
||||||
else cfg.package;
|
});
|
||||||
|
|
||||||
# If you are changing this, please update the description in applyDefaultConfig
|
|
||||||
defaultConfig = {
|
|
||||||
homeassistant.time_zone = config.time.timeZone;
|
|
||||||
http.server_port = cfg.port;
|
|
||||||
} // optionalAttrs (cfg.lovelaceConfig != null) {
|
|
||||||
lovelace.mode = "yaml";
|
|
||||||
};
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
meta.maintainers = teams.home-assistant.members;
|
imports = [
|
||||||
|
# Migrations in NixOS 22.05
|
||||||
|
(mkRemovedOptionModule [ "services" "home-assistant" "applyDefaultConfig" ] "The default config was migrated into services.home-assistant.config")
|
||||||
|
(mkRemovedOptionModule [ "services" "home-assistant" "autoExtraComponents" ] "Components are now parsed from services.home-assistant.config unconditionally")
|
||||||
|
(mkRenamedOptionModule [ "services" "home-assistant" "port" ] [ "services" "home-assistant" "config" "http" "server_port" ])
|
||||||
|
];
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
buildDocsInSandbox = false;
|
||||||
|
maintainers = teams.home-assistant.members;
|
||||||
|
};
|
||||||
|
|
||||||
options.services.home-assistant = {
|
options.services.home-assistant = {
|
||||||
# Running home-assistant on NixOS is considered an installation method that is unsupported by the upstream project.
|
# Running home-assistant on NixOS is considered an installation method that is unsupported by the upstream project.
|
||||||
@@ -81,42 +82,117 @@ in {
|
|||||||
description = "The config directory, where your <filename>configuration.yaml</filename> is located.";
|
description = "The config directory, where your <filename>configuration.yaml</filename> is located.";
|
||||||
};
|
};
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
default = 8123;
|
|
||||||
type = types.port;
|
|
||||||
description = "The port on which to listen.";
|
|
||||||
};
|
|
||||||
|
|
||||||
applyDefaultConfig = mkOption {
|
|
||||||
default = true;
|
|
||||||
type = types.bool;
|
|
||||||
description = ''
|
|
||||||
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.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Currently one side effect of enabling this is that the <literal>http</literal> component will be enabled.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This only takes effect if <literal>config != null</literal> in order to ensure that a manually managed <filename>configuration.yaml</filename> is not overwritten.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkOption {
|
config = mkOption {
|
||||||
default = null;
|
type = types.submodule {
|
||||||
# Migrate to new option types later: https://github.com/NixOS/nixpkgs/pull/75584
|
freeformType = format.type;
|
||||||
type = with lib.types; let
|
options = {
|
||||||
valueType = nullOr (oneOf [
|
# This is a partial selection of the most common options, so new users can quickly
|
||||||
bool
|
# pick up how to match home-assistants config structure to ours. It also lets us preset
|
||||||
int
|
# config values intelligently.
|
||||||
float
|
|
||||||
str
|
homeassistant = {
|
||||||
(lazyAttrsOf valueType)
|
# https://www.home-assistant.io/docs/configuration/basic/
|
||||||
(listOf valueType)
|
name = mkOption {
|
||||||
]) // {
|
type = types.nullOr types.str;
|
||||||
description = "Yaml value";
|
default = null;
|
||||||
emptyValue.value = {};
|
example = "Home";
|
||||||
|
description = ''
|
||||||
|
Name of the location where Home Assistant is running.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
latitude = mkOption {
|
||||||
|
type = types.nullOr (types.either types.float types.str);
|
||||||
|
default = null;
|
||||||
|
example = 52.3;
|
||||||
|
description = ''
|
||||||
|
Latitude of your location required to calculate the time the sun rises and sets.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
longitude = mkOption {
|
||||||
|
type = types.nullOr (types.either types.float types.str);
|
||||||
|
default = null;
|
||||||
|
example = 4.9;
|
||||||
|
description = ''
|
||||||
|
Longitude of your location required to calculate the time the sun rises and sets.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
unit_system = mkOption {
|
||||||
|
type = types.nullOr (types.enum [ "metric" "imperial" ]);
|
||||||
|
default = null;
|
||||||
|
example = "metric";
|
||||||
|
description = ''
|
||||||
|
The unit system to use. This also sets temperature_unit, Celsius for Metric and Fahrenheit for Imperial.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
temperature_unit = mkOption {
|
||||||
|
type = types.nullOr (types.enum [ "C" "F" ]);
|
||||||
|
default = null;
|
||||||
|
example = "C";
|
||||||
|
description = ''
|
||||||
|
Override temperature unit set by unit_system. <literal>C</literal> for Celsius, <literal>F</literal> for Fahrenheit.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
time_zone = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = config.time.timeZone or null;
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
config.time.timeZone or null
|
||||||
|
'';
|
||||||
|
example = "Europe/Amsterdam";
|
||||||
|
description = ''
|
||||||
|
Pick your time zone from the column TZ of Wikipedia’s <link xlink:href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">list of tz database time zones</link>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
in valueType;
|
|
||||||
|
http = {
|
||||||
|
# https://www.home-assistant.io/integrations/http/
|
||||||
|
server_host = mkOption {
|
||||||
|
type = types.either types.str (types.listOf types.str);
|
||||||
|
default = [
|
||||||
|
"0.0.0.0"
|
||||||
|
"::"
|
||||||
|
];
|
||||||
|
example = "::1";
|
||||||
|
description = ''
|
||||||
|
Only listen to incoming requests on specific IP/host. The default listed assumes support for IPv4 and IPv6.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
server_port = mkOption {
|
||||||
|
default = 8123;
|
||||||
|
type = types.port;
|
||||||
|
description = ''
|
||||||
|
The port on which to listen.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
lovelace = {
|
||||||
|
# https://www.home-assistant.io/lovelace/dashboards/
|
||||||
|
mode = mkOption {
|
||||||
|
type = types.enum [ "yaml" "storage" ];
|
||||||
|
default = if cfg.lovelaceConfig != null
|
||||||
|
then "yaml"
|
||||||
|
else "storage";
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
if cfg.lovelaceConfig != null
|
||||||
|
then "yaml"
|
||||||
|
else "storage";
|
||||||
|
'';
|
||||||
|
example = "yaml";
|
||||||
|
description = ''
|
||||||
|
In what mode should the main Lovelace panel be, <literal>yaml</literal> or <literal>storage</literal> (UI managed).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
{
|
{
|
||||||
homeassistant = {
|
homeassistant = {
|
||||||
@@ -130,15 +206,19 @@ in {
|
|||||||
frontend = {
|
frontend = {
|
||||||
themes = "!include_dir_merge_named themes";
|
themes = "!include_dir_merge_named themes";
|
||||||
};
|
};
|
||||||
http = { };
|
http = {};
|
||||||
feedreader.urls = [ "https://nixos.org/blogs.xml" ];
|
feedreader.urls = [ "https://nixos.org/blogs.xml" ];
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
description = ''
|
description = ''
|
||||||
Your <filename>configuration.yaml</filename> as a Nix attribute set.
|
Your <filename>configuration.yaml</filename> as a Nix attribute set.
|
||||||
Beware that setting this option will delete your previous <filename>configuration.yaml</filename>.
|
|
||||||
<link xlink:href="https://www.home-assistant.io/docs/configuration/secrets/">Secrets</link>
|
YAML functions like <link xlink:href="https://www.home-assistant.io/docs/configuration/secrets/">secrets</link>
|
||||||
are encoded as strings as shown in the example.
|
can be passed as a string and will be unquoted automatically.
|
||||||
|
|
||||||
|
Unless this option is explicitly set to <literal>null</literal>
|
||||||
|
we assume your <filename>configuration.yaml</filename> is
|
||||||
|
managed through this module and thereby overwritten on startup.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -147,16 +227,18 @@ in {
|
|||||||
type = types.bool;
|
type = types.bool;
|
||||||
description = ''
|
description = ''
|
||||||
Whether to make <filename>configuration.yaml</filename> writable.
|
Whether to make <filename>configuration.yaml</filename> writable.
|
||||||
This only has an effect if <option>config</option> is set.
|
|
||||||
This will allow you to edit it from Home Assistant's web interface.
|
This will allow you to edit it from Home Assistant's web interface.
|
||||||
|
|
||||||
|
This only has an effect if <option>config</option> is set.
|
||||||
However, bear in mind that it will be overwritten at every start of the service.
|
However, bear in mind that it will be overwritten at every start of the service.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
lovelaceConfig = mkOption {
|
lovelaceConfig = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
type = with types; nullOr attrs;
|
type = types.nullOr format.type;
|
||||||
# from https://www.home-assistant.io/lovelace/yaml-mode/
|
# from https://www.home-assistant.io/lovelace/dashboards/
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
{
|
{
|
||||||
title = "My Awesome Home";
|
title = "My Awesome Home";
|
||||||
@@ -172,8 +254,8 @@ in {
|
|||||||
'';
|
'';
|
||||||
description = ''
|
description = ''
|
||||||
Your <filename>ui-lovelace.yaml</filename> as a Nix attribute set.
|
Your <filename>ui-lovelace.yaml</filename> as a Nix attribute set.
|
||||||
Setting this option will automatically add
|
Setting this option will automatically set <literal>lovelace.mode</literal> to <literal>yaml</literal>.
|
||||||
<literal>lovelace.mode = "yaml";</literal> to your <option>config</option>.
|
|
||||||
Beware that setting this option will delete your previous <filename>ui-lovelace.yaml</filename>
|
Beware that setting this option will delete your previous <filename>ui-lovelace.yaml</filename>
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
@@ -183,8 +265,10 @@ in {
|
|||||||
type = types.bool;
|
type = types.bool;
|
||||||
description = ''
|
description = ''
|
||||||
Whether to make <filename>ui-lovelace.yaml</filename> writable.
|
Whether to make <filename>ui-lovelace.yaml</filename> writable.
|
||||||
This only has an effect if <option>lovelaceConfig</option> is set.
|
|
||||||
This will allow you to edit it from Home Assistant's web interface.
|
This will allow you to edit it from Home Assistant's web interface.
|
||||||
|
|
||||||
|
This only has an effect if <option>lovelaceConfig</option> is set.
|
||||||
However, bear in mind that it will be overwritten at every start of the service.
|
However, bear in mind that it will be overwritten at every start of the service.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
@@ -212,7 +296,7 @@ in {
|
|||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
description = ''
|
description = ''
|
||||||
Home Assistant package to use. By default the tests are disabled, as they take a considerable amout of time to complete.
|
The Home Assistant package to use.
|
||||||
Override <literal>extraPackages</literal> or <literal>extraComponents</literal> in order to add additional dependencies.
|
Override <literal>extraPackages</literal> or <literal>extraComponents</literal> in order to add additional dependencies.
|
||||||
If you specify <option>config</option> and do not set <option>autoExtraComponents</option>
|
If you specify <option>config</option> and do not set <option>autoExtraComponents</option>
|
||||||
to <literal>false</literal>, overriding <literal>extraComponents</literal> will have no effect.
|
to <literal>false</literal>, overriding <literal>extraComponents</literal> will have no effect.
|
||||||
@@ -220,21 +304,6 @@ in {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
autoExtraComponents = mkOption {
|
|
||||||
default = true;
|
|
||||||
type = types.bool;
|
|
||||||
description = ''
|
|
||||||
If set to <literal>true</literal>, the components used in <literal>config</literal>
|
|
||||||
are set as the specified package's <literal>extraComponents</literal>.
|
|
||||||
This in turn adds all packaged dependencies to the derivation.
|
|
||||||
You might still see import errors in your log.
|
|
||||||
In this case, you will need to package the necessary dependencies yourself
|
|
||||||
or ask for someone else to package them.
|
|
||||||
If a dependency is packaged but not automatically added to this list,
|
|
||||||
you might need to specify it in <literal>extraPackages</literal>.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
openFirewall = mkOption {
|
openFirewall = mkOption {
|
||||||
default = false;
|
default = false;
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
|
|||||||
Reference in New Issue
Block a user