Home-Assistant Service
Defined in /modules/services/home-assistant.nix.
This NixOS module is a service that sets up a Home-Assistant instance.
Compared to the stock module from nixpkgs, this one sets up, in a fully declarative manner LDAP and SSO integration.
Features
Declarative creation of users, admin or not.
Backup through the backup block. Manual.
Integration with the dashboard contract for displaying user facing application in a dashboard. Manual
Not yet: declarative SSO.
Usage
Initial Configuration
The following snippet enables Home-Assistant and makes it available under the ha.example.com endpoint.
shb.home-assistant = {
enable = true;
subdomain = "ha";
domain = "example.com";
config = {
name = "SelfHostBlocks - Home Assistant";
country.source = config.shb.sops.secret."home-assistant/country".result.path;
latitude.source = config.shb.sops.secret."home-assistant/latitude_home".result.path;
longitude.source = config.shb.sops.secret."home-assistant/longitude_home".result.path;
time_zone.source = config.shb.sops.secret."home-assistant/time_zone".result.path;
unit_system = "metric";
};
};
shb.sops.secret."home-assistant/country".request = {
mode = "0440";
owner = "hass";
group = "hass";
restartUnits = [ "home-assistant.service" ];
};
shb.sops.secret."home-assistant/latitude_home".request = {
mode = "0440";
owner = "hass";
group = "hass";
restartUnits = [ "home-assistant.service" ];
};
shb.sops.secret."home-assistant/longitude_home".request = {
mode = "0440";
owner = "hass";
group = "hass";
restartUnits = [ "home-assistant.service" ];
};
shb.sops.secret."home-assistant/time_zone".request = {
mode = "0440";
owner = "hass";
group = "hass";
restartUnits = [ "home-assistant.service" ];
};
This assumes secrets are setup with SOPS as mentioned in the secrets setup section of the manual.
Any item in the config can be passed a secret, which means it will not appear
in the /nix/store and instead be added to the config file out of band, here using sops.
To do that, append .source to the settings name and give it the path to the secret.
I advise using secrets to set personally identifiable information, like shown in the snippet. Especially if you share your repository publicly.
Home-Assistant through HTTPS
Note
We will build upon the Initial Configuration section, so please follow that first.
If the shb.ssl block is used (see manual on how to set it up),
the instance will be reachable at https://ha.example.com.
Here is an example with Let’s Encrypt certificates, validated using the HTTP method. First, set the global configuration for your domain:
shb.certs.certs.letsencrypt."example.com" = {
domain = "example.com";
group = "nginx";
reloadServices = [ "nginx.service" ];
adminEmail = "myemail@mydomain.com";
};
Then you can tell Home-Assistant to use those certificates.
shb.certs.certs.letsencrypt."example.com".extraDomains = [ "ha.example.com" ];
shb.home-assistant = {
ssl = config.shb.certs.certs.letsencrypt."example.com";
};
With LDAP Support
Note
We will build upon the HTTPS section, so please follow that first.
We will use the LLDAP block provided by Self Host Blocks. Assuming it has been set already, add the following configuration:
shb.home-assistant.ldap
enable = true;
host = "127.0.0.1";
port = config.shb.lldap.webUIListenPort;
# This is the default:
# userGroup = "homeassistant_user";
# adminGroup = "homeassistant_admin";
};
shb.lldap.ensureGroups = {
${config.shb.home-assistant.ldap.userGroup} = { };
${config.shb.home-assistant.ldap.adminGroup} = { };
};
shb.lldap.ensureUsers.homeAssistantAdmin = {
groups = [
config.shb.home-assistant.ldap.adminGroup
];
};
shb.lldap.ensureUsers.homeAssistantUser = {
groups = [
config.shb.home-assistant.ldap.userGroup
];
};
This will create a LDAP group declaratively
and add the user homeAssitantUser as a user
and the user homeAssitantAdmin as an admin.
LDAP users can be added to the groups imperatively too through the LLDAP web UI.
With SSO Support
Warning
This is not implemented yet. Any contributions (issue #12) are welcomed!
Backup
Backing up Home-Assistant using the Restic block is done like so:
shb.restic.instances."home-assistant" = {
request = config.shb.home-assistant.backup;
settings = {
enable = true;
};
};
The name "home-assistant" in the instances can be anything.
The config.shb.home-assistant.backup option provides what directories to backup.
You can define any number of Restic instances to backup Home-Assistant multiple times.
You will then need to configure more options like the repository,
as explained in the restic documentation.
Application Dashboard
Integration with the dashboard contract is provided by the dashboard option.
For example using the Homepage service:
{
shb.homepage.servicesGroups.Home.services.HomeAssistant = {
sortOrder = 1;
dashboard.request = config.shb.home-assistant.dashboard.request;
settings.icon = "si-homeassistant";
};
}
The icon needs to be set manually otherwise it is not displayed correctly.
An API key can be set to show extra info:
{
shb.homepage.servicesGroups.Home.services.HomeAssistant = {
apiKey.result = config.shb.sops.secret."home-assistant/homepageApiKey".result;
};
shb.sops.secret."home-assistant/homepageApiKey".request =
config.shb.homepage.servicesGroups.Home.services.HomeAssistant.apiKey.request;
}
Custom widgets can be set using Home Assistant templating:
{
shb.homepage.servicesGroups.Home.services.HomeAssistant = {
settings.widget.custom = [
{
template = "{{ states('sensor.power_consumption_power_consumption', with_unit=True, rounded=True) }}";
label = "energy now";
}
{
state = "sensor.power_consumption_daily_power_consumption";
label = "energy today";
}
];
};
}
Extra Components
Packaged components can be found in the documentation of the corresponding option services.home-assistant.extraComponents
When you find an interesting one add it to the option:
services.home-assistant.extraComponents = [
"backup"
"bluetooth"
"esphome"
"assist_pipeline"
"conversation"
"piper"
"wake_word"
"whisper"
"wyoming"
];
Some components are not available as extra components, but need to be added as cusotm components. If the component is not packaged, you’ll need to use a custom component.
Custom Components
Note
I’m still confused for why is there a difference between custom components and extra components.
Available custom components can be found by searching packages for home-assistant-custom-components.
Add them like so:
services.home-assistant.customComponents = with pkgs.home-assistant-custom-components; [
adaptive_lighting
];
To add a not packaged component, you can get inspiration from existing [packaged components.
To help you package a custom component nixpkgs code to package it
using the pkgs.buildHomeAssistantComponent function.
When done, add it to the same services.home-assistant.customComponents option.
Also, don’t hesitate to upstream it to nixpkgs.
Custom Lovelace Modules
To add custom Lovelace UI elements, add them to the services.home-assistant.customLovelaceModules option.
Available custom components can be found by searching packages for home-assistant-custom-lovelace-modules.
services.home-assistant.customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
mini-graph-card
mini-media-player
hourly-weather
weather-card
];
Extra Packages
This is really only needed if by mischance, one of the components added earlier fail because of a missing Python3 package when the home-assistant systemd service is started. Usually, the required module will be shown in the traceback. To know to which nixpkgs package this Python3 package correspond, search for a package in the python3XXPackages set.
services.home-assistant.extraPackages = python3Packages: with python3Packages; [
grpcio
];
Extra Groups
Some components need access to hardware components which mean the home-assistant user
hass must be added to some Unix group.
For example, the hass user must be added to the dialout group for the Sonoff component.
There’s no systematic way to know this apart reading the logs when a home-assistant component fails to start.
users.users.hass.extraGroups = [ "dialout" ];
Voice
Text to speech (TTS) and speech to text (STT) can be added with the stock nixpkgs options. The most performance hungry one is STT. If you don’t have a good CPU or better a GPU, you won’t be able to use medium to big models. From my own experience using a low-end CPU, voice is pretty much unusable like that, even with mini models.
Here is the configuration I use on a low-end CPU:
shb.home-assistant.voice.text-to-speech = {
"fr" = {
enable = true;
voice = "fr-siwis-medium";
uri = "tcp://0.0.0.0:10200";
speaker = 0;
};
"en" = {
enable = true;
voice = "en_GB-alba-medium";
uri = "tcp://0.0.0.0:10201";
speaker = 0;
};
};
shb.home-assistant.voice.speech-to-text = {
"tiny-fr" = {
enable = true;
model = "base-int8";
language = "fr";
uri = "tcp://0.0.0.0:10300";
device = "cpu";
};
"tiny-en" = {
enable = true;
model = "base-int8";
language = "en";
uri = "tcp://0.0.0.0:10301";
device = "cpu";
};
};
systemd.services.wyoming-faster-whisper-tiny-en.environment."HF_HUB_CACHE" = "/tmp";
systemd.services.wyoming-faster-whisper-tiny-fr.environment."HF_HUB_CACHE" = "/tmp";
shb.home-assistant.voice.wakeword = {
enable = true;
uri = "tcp://127.0.0.1:10400";
preloadModels = [
"ok_nabu"
];
};
Music Assistant
To add Music Assistant under the ma.example.com domain
with two factor SSO authentication, use the following configuration.
This assumes the SSL and SSO blocks are configured.
services.music-assistant = {
enable = true;
providers = [
"airplay"
"hass"
"hass_players"
"jellyfin"
"radiobrowser"
"sonos"
"spotify"
];
};
shb.nginx.vhosts = [
{
subdomain = "ma";
domain = "example.com";
ssl = config.shb.certs.certs.letsencrypt.${domain};
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
upstream = "http://127.0.0.1:8095";
autheliaRules = [{
domain = "ma.${domain}";
policy = "two_factor";
subject = ["group:music-assistant_user"];
}];
}
];
Debug
In case of an issue, check the logs for systemd service home-assistant.service.
Enable verbose logging by setting the shb.home-assistant.debug boolean to true.
Access the database with sudo -u home-assistant psql.
Options Reference
-
shb.home-assistant.enable -
Whether to enable selfhostblocks.home-assistant.
Type: boolean
Default:
falseExample:
trueDeclared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup -
Backup configuration.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup.request -
Request part of the backup contract.
Options set by the requester module enforcing how to backup files.
Type: submodule
Default:
""Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup.request.excludePatterns -
File patterns to exclude.
Type: list of string
Default:
[ ]Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup.request.hooks -
Hooks to run around the backup.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup.request.hooks.afterBackup -
Hooks to run after backup.
Type: list of string
Default:
[ ]Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup.request.hooks.beforeBackup -
Hooks to run before backup.
Type: list of string
Default:
[ ]Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup.request.sourceDirectories -
Directories to backup.
Type: non-empty (list of string)
Default:
[ "/var/lib/hass/backups" ]Example:
"/var/lib/vaultwarden"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup.request.user -
Unix user doing the backups.
Type: string
Default:
"hass"Example:
"vaultwarden"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup.result -
Result part of the backup contract.
Options set by the provider module that indicates the name of the backup and restore scripts.
Type: submodule
Default:
""Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup.result.backupService -
Name of service backing up the database.
This script can be ran manually to backup the database:
$ systemctl start backup.serviceType: string
Default:
"backup.service"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.backup.result.restoreScript -
Name of script that can restore the database. One can then list snapshots with:
$ restore snapshots <snapshot 1> <metadata> <snapshot 2> <metadata>And restore the database with:
$ restore restore <snapshot 1>Type: string
Default:
"restore"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.config -
See all available settings at https://www.home-assistant.io/docs/configuration/basic/
Type: open submodule of attribute set of string
Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.config.country -
Two letter country code where this instance is located.
Type: string or (submodule)
Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.config.latitude -
Latitude where this instance is located.
Type: string or (submodule)
Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.config.longitude -
Longitude where this instance is located.
Type: string or (submodule)
Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.config.name -
Name of the Home Assistant instance.
Type: string or (submodule)
Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.config.time_zone -
Timezone of this instance.
Type: string or (submodule)
Example:
"America/Los_Angeles"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.config.unit_system -
Unit system of this instance.
Type: string or one of “metric”, “us_customary”
Example:
"metric"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.dashboard -
Dashboard contract consumer
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.dashboard.request -
Request part of the dashboard contract.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.dashboard.request.externalUrl -
URL at which the service can be accessed.
This URL should go through the reverse proxy.
Type: string
Default:
"https://\${config.shb.home-assistant.subdomain}.\${config.shb.home-assistant.domain}"Example:
"https://jellyfin.example.com"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.dashboard.request.internalUrl -
URL at which the service can be accessed directly.
This URL should bypass the reverse proxy. It can be used for example to ping the service and making sure it is up and running correctly.
Type: null or string
Default:
"http://127.0.0.1:\${config.services.home-assistant.config.http.server_port}"Example:
"http://127.0.0.1:8081"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.dashboard.result -
Result part of the dashboard contract.
No option is provided here.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.domain -
domain under which home-assistant will be served.
Type: string
Example:
"mydomain.com"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ldap -
LDAP Integration App. Manual
Enabling this app will create a new LDAP configuration or update one that exists with the given host.
Also, enabling LDAP will skip onboarding otherwise Home Assistant gets into a cyclic lock.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ldap.enable -
Whether to enable LDAP app…
Type: boolean
Default:
falseExample:
trueDeclared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ldap.adminGroup -
Group users must belong to to be able to login as an admin.
Type: string
Default:
"homeassistant_admin"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ldap.debug -
Whether to enable verbose output for LDAP app…
Type: boolean
Default:
falseExample:
trueDeclared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ldap.host -
Host serving the LDAP server.
If set, the Home Assistant auth will be disabled. To keep it, set
keepDefaultAuthtotrue.Type: string
Default:
"127.0.0.1"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ldap.keepDefaultAuth -
Keep Home Assistant auth active, even if LDAP is configured. Usually, you want to enable this to transfer existing users to LDAP and then you can disabled it.
Type: boolean
Default:
falseDeclared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ldap.port -
Port of the service serving the LDAP server.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
389Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ldap.userGroup -
Group users must belong to to be able to login as a user.
Type: string
Default:
"homeassistant_user"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ssl -
Path to SSL files
Type: null or (open submodule of anything)
Default:
nullDeclared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ssl.paths -
Paths where the files for the certificate will be located.
This option is the contract output of the
shb.certs.certsSSL block.Type: open submodule of anything
Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ssl.paths.cert -
Path to the cert file.
Type: absolute path
Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ssl.paths.key -
Path to the key file.
Type: absolute path
Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.ssl.systemdService -
Systemd oneshot service used to generate the certificate. Ends with the
.servicesuffix.Use this if downstream services must wait for the certificates to be generated before starting.
Type: string
Example:
"cert-generator.service"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.subdomain -
Subdomain under which home-assistant will be served.
Type: string
Example:
"ha"Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.voice -
Options related to voice service.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.voice.speech-to-text -
Wyoming piper servers.
https://search.nixos.org/options?channel=23.11&from=0&size=50&sort=relevance&type=packages&query=services.wyoming.piper.servers
Type: attribute set of anything
Default:
{ }Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.voice.text-to-speech -
Wyoming faster-whisper servers.
https://search.nixos.org/options?channel=23.11&from=0&size=50&sort=relevance&type=packages&query=services.wyoming.faster-whisper.servers
Type: attribute set of anything
Default:
{ }Declared by:
<selfhostblocks/modules/services/home-assistant.nix> -
shb.home-assistant.voice.wakeword -
Wyoming open wakework servers.
https://search.nixos.org/options?channel=23.11&from=0&size=50&sort=relevance&type=packages&query=services.wyoming.openwakeword
Type: anything
Default:
{ enable = false; }Declared by:
<selfhostblocks/modules/services/home-assistant.nix>