2018-01-23 09:51:13 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.services.home-assistant;
|
|
|
|
|
2018-04-23 22:12:19 +00:00
|
|
|
# cfg.config != null can be assumed here
|
|
|
|
configFile = pkgs.writeText "configuration.json"
|
|
|
|
(builtins.toJSON (if cfg.applyDefaultConfig then
|
|
|
|
(lib.recursiveUpdate defaultConfig cfg.config) else cfg.config));
|
2018-02-01 12:42:07 +00:00
|
|
|
|
|
|
|
availableComponents = pkgs.home-assistant.availableComponents;
|
|
|
|
|
2018-02-04 00:30:47 +00:00
|
|
|
# Given component "parentConfig.platform", returns whether config.parentConfig
|
|
|
|
# is a list containing a set with set.platform == "platform".
|
|
|
|
#
|
|
|
|
# For example, the component sensor.luftdaten is used as follows:
|
|
|
|
# config.sensor = [ {
|
|
|
|
# platform = "luftdaten";
|
|
|
|
# ...
|
|
|
|
# } ];
|
|
|
|
useComponentPlatform = component:
|
|
|
|
let
|
|
|
|
path = splitString "." component;
|
|
|
|
parentConfig = attrByPath (init path) null cfg.config;
|
|
|
|
platform = last path;
|
|
|
|
in isList parentConfig && any
|
|
|
|
(item: item.platform or null == platform)
|
|
|
|
parentConfig;
|
|
|
|
|
2018-02-01 12:42:07 +00:00
|
|
|
# Returns whether component is used in config
|
2018-02-04 00:30:47 +00:00
|
|
|
useComponent = component:
|
|
|
|
hasAttrByPath (splitString "." component) cfg.config
|
|
|
|
|| useComponentPlatform component;
|
2018-02-01 12:42:07 +00:00
|
|
|
|
|
|
|
# List of components used in config
|
|
|
|
extraComponents = filter useComponent availableComponents;
|
|
|
|
|
|
|
|
package = if cfg.autoExtraComponents
|
|
|
|
then (cfg.package.override { inherit extraComponents; })
|
|
|
|
else cfg.package;
|
|
|
|
|
2018-04-21 14:32:09 +00:00
|
|
|
# If you are changing this, please update the description in applyDefaultConfig
|
|
|
|
defaultConfig = {
|
|
|
|
homeassistant.time_zone = config.time.timeZone;
|
|
|
|
http.server_port = (toString cfg.port);
|
|
|
|
};
|
|
|
|
|
2018-01-23 09:51:13 +00:00
|
|
|
in {
|
|
|
|
meta.maintainers = with maintainers; [ dotlambda ];
|
|
|
|
|
|
|
|
options.services.home-assistant = {
|
|
|
|
enable = mkEnableOption "Home Assistant";
|
|
|
|
|
|
|
|
configDir = mkOption {
|
|
|
|
default = "/var/lib/hass";
|
|
|
|
type = types.path;
|
|
|
|
description = "The config directory, where your <filename>configuration.yaml</filename> is located.";
|
|
|
|
};
|
|
|
|
|
2018-04-21 14:32:09 +00:00
|
|
|
port = mkOption {
|
|
|
|
default = 8123;
|
|
|
|
type = types.int;
|
|
|
|
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.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2018-01-23 09:51:13 +00:00
|
|
|
config = mkOption {
|
|
|
|
default = null;
|
|
|
|
type = with types; nullOr attrs;
|
|
|
|
example = literalExample ''
|
|
|
|
{
|
|
|
|
homeassistant = {
|
|
|
|
name = "Home";
|
|
|
|
time_zone = "UTC";
|
|
|
|
};
|
|
|
|
frontend = { };
|
|
|
|
http = { };
|
2018-02-01 12:42:07 +00:00
|
|
|
feedreader.urls = [ "https://nixos.org/blogs.xml" ];
|
2018-01-23 09:51:13 +00:00
|
|
|
}
|
|
|
|
'';
|
|
|
|
description = ''
|
|
|
|
Your <filename>configuration.yaml</filename> as a Nix attribute set.
|
|
|
|
Beware that setting this option will delete your previous <filename>configuration.yaml</filename>.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
package = mkOption {
|
|
|
|
default = pkgs.home-assistant;
|
|
|
|
defaultText = "pkgs.home-assistant";
|
|
|
|
type = types.package;
|
|
|
|
example = literalExample ''
|
|
|
|
pkgs.home-assistant.override {
|
|
|
|
extraPackages = ps: with ps; [ colorlog ];
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
description = ''
|
|
|
|
Home Assistant package to use.
|
2018-02-01 12:42:07 +00:00
|
|
|
Override <literal>extraPackages</literal> in order to add additional dependencies.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
autoExtraComponents = mkOption {
|
|
|
|
default = true;
|
|
|
|
type = types.bool;
|
|
|
|
description = ''
|
2018-02-03 08:53:54 +00:00
|
|
|
If set to <literal>true</literal>, the components used in <literal>config</literal>
|
2018-02-01 12:42:07 +00:00
|
|
|
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>.
|
2018-01-23 09:51:13 +00:00
|
|
|
'';
|
|
|
|
};
|
2018-05-22 01:14:04 +00:00
|
|
|
|
|
|
|
openFirewall = mkOption {
|
|
|
|
default = false;
|
|
|
|
type = types.bool;
|
|
|
|
description = "Whether to open the firewall for the specified port.";
|
|
|
|
};
|
2018-01-23 09:51:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
2018-05-22 01:14:04 +00:00
|
|
|
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
|
|
|
|
|
2018-01-23 09:51:13 +00:00
|
|
|
systemd.services.home-assistant = {
|
|
|
|
description = "Home Assistant";
|
|
|
|
after = [ "network.target" ];
|
|
|
|
preStart = lib.optionalString (cfg.config != null) ''
|
2018-04-21 14:33:32 +00:00
|
|
|
config=${cfg.configDir}/configuration.yaml
|
|
|
|
rm -f $config
|
|
|
|
${pkgs.remarshal}/bin/json2yaml -i ${configFile} -o $config
|
|
|
|
chmod 444 $config
|
2018-01-23 09:51:13 +00:00
|
|
|
'';
|
|
|
|
serviceConfig = {
|
2018-04-21 14:32:09 +00:00
|
|
|
ExecStart = "${package}/bin/hass --config '${cfg.configDir}'";
|
2018-01-23 09:51:13 +00:00
|
|
|
User = "hass";
|
|
|
|
Group = "hass";
|
|
|
|
Restart = "on-failure";
|
|
|
|
ProtectSystem = "strict";
|
|
|
|
ReadWritePaths = "${cfg.configDir}";
|
|
|
|
PrivateTmp = true;
|
2018-04-21 14:32:09 +00:00
|
|
|
RemoveIPC = true;
|
2018-01-23 09:51:13 +00:00
|
|
|
};
|
2018-03-18 11:46:36 +00:00
|
|
|
path = [
|
|
|
|
"/run/wrappers" # needed for ping
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.targets.home-assistant = rec {
|
|
|
|
description = "Home Assistant";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
wants = [ "home-assistant.service" ];
|
|
|
|
after = wants;
|
2018-01-23 09:51:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
users.extraUsers.hass = {
|
|
|
|
home = cfg.configDir;
|
|
|
|
createHome = true;
|
|
|
|
group = "hass";
|
|
|
|
uid = config.ids.uids.hass;
|
|
|
|
};
|
|
|
|
|
|
|
|
users.extraGroups.hass.gid = config.ids.gids.hass;
|
|
|
|
};
|
|
|
|
}
|