Home Assistant: Difference between revisions
→Snippets: Reorder declarative/ui defined scenes to be closer to similar automation section |
Show logo from mediawiki commons |
||
Line 1: | Line 1: | ||
[https://www.home-assistant.io/ Home Assistant] is an open source home automation software that puts local control and privacy first. Powered by a worldwide community of tinkerers and DIY enthusiasts. | [[File:New Home Assistant logo.svg|right|250px]] | ||
[https://www.home-assistant.io/ Home Assistant] is an open source home automation software that puts local control and privacy first. Powered by a worldwide community of tinkerers and DIY enthusiasts. | |||
= Installation methods = | = Installation methods = |
Revision as of 12:14, 9 May 2024
Home Assistant is an open source home automation software that puts local control and privacy first. Powered by a worldwide community of tinkerers and DIY enthusiasts.
Installation methods
Upstream has defined several installation methods which they are willing to support. The NixOS module is not one of them. When you find a problem you can still report it upstream, if you are certain that the issue is relevant to upstream supported installation methods as well. If not, or if in doubt, please open an isssue on the nixpkgs issue tracker or visit the NixOS Home-Automation (#homeautomation:nixos.org
) Matrix room.
Upstream supported
Virtual machine
You could run your Home Assistant in a virtual machine, with your NixOS host providing the hypervisor.
- Install Home Assistant Operating System (home-assistant.io)
- NixOS: Headless Home Assistant VM (myme.no)
TODO: add example configuration
OCI container
You could run your Home Assistant in any kind of container runtime
Remember to allow port 8123
networking.firewall.allowedTCPPorts = [ 8123 ];
Example Configuration
Adding the following to your `configuration.nix` will bring up home-assistant listening on `:8123` on the host interface.
{
virtualisation.oci-containers = {
backend = "podman";
containers.homeassistant = {
volumes = [ "home-assistant:/config" ];
environment.TZ = "Europe/Berlin";
image = "ghcr.io/home-assistant/home-assistant:stable"; # Warning: if the tag does not change, the image will not be updated
extraOptions = [
"--network=host"
"--device=/dev/ttyACM0:/dev/ttyACM0" # Example, change this to match your own hardware
];
};
};
}
NixOS Module
You could run home-assistant using the NixOS module system at services-home-assistant
. As of 2022-08-04 (2022.8.1) we have support for roughly 85.6% (885/1033) of components, which requires around 711 python dependencies.
Right now there are two major ways of running home-assistant using the module system:
- a) Using a fully declarative configuration
- b) Using a custom configuration, supplied by verbatim home-assistant configuration files
Using a custom configuration has the drawback, that we cannot automatically recognize and install component dependencies and it is not clear that we will continue to support these kinds of setups going forward. If you are using such a setup, please speak up in the Home-Automation room on Matrix (#homeautomation:nixos.org
).
Declarative configuration
Set up your home-assistant by configuring the services.home-assistant.config
attribute set as if it were your home-assistant YAML configuration. The module parses the root and platforms level to automatically discover integrations used and will add their dependencies to your home-assistant package.
The following is a minimal starting configuration, that has all the dependencies that are required to complete the initial configuration flow, that creates your first user.
{
services.home-assistant = {
enable = true;
extraComponents = [
# Components required to complete the onboarding
"esphome"
"met"
"radio_browser"
];
config = {
# Includes dependencies for a basic setup
# https://www.home-assistant.io/integrations/default_config/
default_config = {};
};
};
}
If not using a reverse-proxy and you just want unencrypted access on a local network don't forget to update your firewall configuration to expose the port home-assistant is running on.
{
networking.firewall.allowedTCPPorts = [ <other ports> 8123 ];
}
OpenSSL 1.1 is marked as insecure, refusing to evaluate
As of Home Assistant 2023.12.0 many components started depending on the matter
integration. It unfortunately still relies on OpenSSL 1.1, which has gone end of life in 2023/09. For home-assistant
deployments to work after this release you most likely need to allow this insecure dependency in our system configuration.
{
nixpkgs.config.permittedInsecurePackages = [
"openssl-1.1.1w"
];
}
First start
On your first start you may see multiple ModuleNotFoundError
in Home Assistants journal log. These are dependencies required to set up devices Home Assistant already found on the network.
The appropriate component to load can be looked up in the component-packages.nix
file, that gets auto-generated as part of the packaging process.
For example we can map the following error to
ModuleNotFoundError: No module named 'aioesphomeapi'
the esphome
module quite easily.
{
version = "2022.8.0";
components = {
[...]
"esphome" = ps: with ps; [
aioesphomeapi
aiohttp-cors
ifaddr
zeroconf
];
[...]
Using components without YAML configuration
When a component has no YAML configuration its dependencies can in theory be installed by mentioning the component name in services.home-assistant.config.wled = {};
. This is deprecated, since Home Assistant will usually complain about the config having been migrated into the graphical user interface.
In recent versions of the home-assistant this use case has become more prominent and therefore received a more straightforward implementation, that also ensures that the component is still provided by Home Assistant.
{
services.home-assistant.extraComponents = [
"wled"
];
}
Making additional python packages available
We control the dependencies we pass into the Home Assistant python environment through module options that make the dependencies available, when their relative component was declaratively mentioned.
For other use cases like PostgreSQL support in the recorder component or the use of custom components, we provide an option to inject arbitrary dependencies from nixpkgs available python package set.
{
services.home-assistant.extraPackages = python3Packages: with python3Packages; [
# recorder postgresql support
psycopg2
# miele@home
flatdict
(callPackage ./pymiele.nix)
];
}
Using custom components
We provide a way to declaratively manage custom components through the NixOS module with the services.home-assistant.customComponents option.
Custom components can be found under pkgs.home-assistant-custom-components.
Using custom lovelace modules
We provide a way to declaratively manage custom lovelace modules through the NixOS module with the services.home-assistant.customLovelaceModules option.
Custom components can be found under pkgs.home-assistant-custom-lovelace-modules.
Reusing existing YAML configuration
The module also supports passing it an existing configuration, however that comes with certain drawbacks. For example we cannot automatically detect the components, that your configuration requires. In that scenario you will need to resolve dependencies manually using the packages extraComponents
parameter. Also you will be unable to reuse configuration values between parts of your NixOS configuration. A barebones setup to get you started may look like this:
{
services.home-assistant = {
enable = true;
# Pass the path to the directory where your configuration.yaml
# resides, /var/lib/hass might be a good location.
configDir = /var/lib/hass;
# Override the package to handle dependency management manually
package = (pkgs.home-assistant.override {
# https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/home-assistant/component-packages.nix
extraComponents = [
"default_config"
"esphome"
"met"
];
extraPackages = ps: with ps; [
# Are you using a database server for your recorder?
# https://www.home-assistant.io/integrations/recorder/
#mysqlclient
#psycopg2
];
})
};
}
You may find the following script helpful. It looks up missing dependencies from the home-assistant.service
systemd unit journal: https://gist.github.com/AngryAnt/74c047a2b8438517c822ffdd9663aa57
Running a recent version using an overlay
Home Assistant is a fast-paced open source project, that currently features one major release every month, and a handful of minor ones in between. Firmwares and API endpoints tend to change from time to time, so Home Assistant and its bindings need to keep up to keep things work. The version we provide at the branch off is just a snapshot in time, and does not receive any updates, because there would just be too many dependencies to backport. But with NixOS it is still possible to use the version in nixpkgs/unstable by creating an overlay and using the module from nixos-unstable.
let
# Track NixOS unstable via nix-channel, or replace it with something like niv at your own discretion
# nix-channel --add http://nixos.org/channels/nixos-unstable nixos-unstable
unstable = import <nixos-unstable> {};
in
{
nixpkgs.overlays = [
(self: super: {
inherit (unstable) home-assistant;
})
];
disabledModules = [
"services/home-automation/home-assistant.nix"
];
imports = [
<nixos-unstable/nixos/modules/services/home-automation/home-assistant.nix>
];
}
Snippets
Reverse Proxying with nginx
If you run a public Home Assistant instance it is a good idea to enable SSL/TLS. The following configuration generates a certificate using letsencrypt:
services.home-assistant.config.http = {
server_host = "::1";
trusted_proxies = [ "::1" ];
use_x_forwarded_for = true;
};
services.nginx = {
recommendedProxySettings = true;
virtualHosts."home.example.com" = {
forceSSL = true;
enableACME = true;
extraConfig = ''
proxy_buffering off;
'';
locations."/" = {
proxyPass = "http://[::1]:8123";
proxyWebsockets = true;
};
};
};
Using PostgreSQL
Home Assistant supports PostgreSQL as a database backend for, among other things, its logger and history components. It's a lot more scalable and typically provides faster response times than the SQLite database, that is used by default.
Remember to make backups of your database, for Home Assistant is becoming more and more stateful and has moved away from a completely declarative YAML configuration for new and core components.
Also note that when overridding the package you may want to disable install checks as they tend to take a long time to complete.
services.home-assistant = {
package = (pkgs.home-assistant.override {
extraPackages = py: with py; [ psycopg2 ];
}).overrideAttrs (oldAttrs: {
doInstallCheck = false;
});
config.recorder.db_url = "postgresql://@/hass";
};
services.postgresql = {
enable = true;
ensureDatabases = [ "hass" ];
ensureUsers = [{
name = "hass";
ensureDBOwnership = true;
}];
};
Combine declarative and UI defined automations
You can also declaratively define your automations while still being able to define them in Home Assistant UI. Automations defined in UI are stored in /var/lib/hass/automations.yaml
. If you are not planning on using UI defined automations, then you can define them under services.home-assistant.config.automation
, otherwise split them into services.home-assistant.config."automation manual"
and services.home-assistant.config."automation ui"
, like so:
services.home-assistant.config =
{
"automation manual" = [
{
alias = "living room plug off";
trigger = {
platform = "time";
at = "22:00";
};
action = {
type = "turn_off";
device_id = "someID"; #Inspect yaml of automation created in UI
entity_id = "switch.living_room_plug";
domain = "switch";
};
}
];
"automation ui" = "!include automations.yaml";
}
Combine declarative and UI defined scenes
Same as with automations, scenes can also be configured both declaratively and from within the UI:
services.home-assistant.config."scene manual" = [
# declarative scenes go here
];
services.home-assistant.config."scene ui" = "!include scenes.yaml";
More Declarative Nix Configuration Examples
Entity Customization
You can declaratively define how entities appear in the GUI with respect to their display names (friendly_name) the "show as" (device_class) and the icon displayed (icon). See this page for more documentation and how the yaml will ultimately be generated: https://www.home-assistant.io/docs/configuration/customizing-devices/.
config = {
default_config = {};
homeassistant = {
# MUST be at the top or will break entire configuration
customize = {
# Declare all "entity_id" objects here at this level to customize them
"binary_sensor.name" = {
# Custom name however you want the entity to appear in the GUI
friendly_name = "friendlyname";
# See https://www.home-assistant.io/integrations/binary_sensor/ for documentation
device_class = "deviceclass";
# See https://www.home-assistant.io/docs/configuration/customizing-devices/#icon for documentation
icon = "mdi:iconname";
};
};
};
};
Alarm Control Panel
You can declaratively define your own Alarm Control Panel which will appear on the GUI and have entities available to be changed via declaratively created automations. See https://www.home-assistant.io/integrations/manual/ for more documentation.
config = {
default_config = {};
homeassistant = {
# On same level as automations
"alarm_control_panel" = [
{
platform = "manual";
name = "Home Alarm";
code_arm_required = "false";
arming_time = "30";
delay_time = "20";
trigger_time = "4";
disarmed = {
trigger_time = "0";
};
armed_home = {
arming_time = "0";
delay_time = "0";
};
armed_night = {
arming_time = "0";
delay_time = "0";
};
}
];
Groups / Helpers
You can declaratively define groups rather than setting them up in the GUI, and customize their unique_id, platform, type, and entitiy_id's associated. See https://www.home-assistant.io/integrations/group/ for more documentation. Can be used in conjunction with "Entity Customization" section above for additional flexibility by plugging in the "unique_id" then changing the "friendly_name", "icon", "device_class" etc.
Binary Sensor Group
Example of Door and Window Sensor Group that could be used in an Automation for triggering an alarm system if any door or window is opened.
# Door and Window Sensor Group
"binary_sensor" = [
{
unique_id = "binary_sensor.all_door_and_window_sensors";
platform = "group";
device_class = "door";
entities = [
"binary_sensor.sensor_1"
"binary_sensor.sensor_2"
"binary_sensor.sensor_3"
];
}
];
Sensor Group
Example of Sensor group using "min" mode that could be used in an Automation to trigger a Low Battery Alert across all batteries in the group.
# Sensor Battery Group
"sensor" = [
{
unique_id = "sensor.all_batteries";
platform = "group";
type = "min";
# Use this or else if any go to "unknown" the group will show unknown
ignore_non_numeric = "true";
device_class = "battery";
entities = [
"sensor.battery_1"
"sensor.battery_2"
"sensor.battery_3"
];
}
];
Automations
Automation with a Condition
{
alias = "Name To Display in Automations List";
trigger = {
platform = "state";
entity_id = "binary_sensor.someid1";
to = "off";
for = "00:10:00";
};
condition = {
condition = "state";
entity_id = "binary_sensor.someid2";
state = "on";
};
action = {
service = "light.turn_off";
entity_id = "light.someid";
};
}
Automation with Multiple Conditions, Multiple Actions
{
alias = "Name in Automations GUI";
trigger = {
platform = "state";
entity_id = "binary_sensor.someid";
to = "on";
};
condition = [
{
condition = "state";
entity_id = "sun.sun";
state = "below_horizon";
}
{
condition = "state";
entity_id = "light.someid";
state = "off";
}
];
action = [
{
service = "notify.notify";
data = {
message = "Some Notification";
};
}
{
service = "siren.turn_on";
entity_id = "siren.someid";
}
];
}
Trigger Using Numeric State
{
alias = "Some Name";
trigger = {
platform = "numeric_state";
entity_id = "sensor.batteries";
below = "45";
};
action = {
service = "notify.notify";
data = {
message = "Low Battery Detected";
};
};
}
Trigger Checking for Entity State Missing / Changing to Unknown
{
alias = "Object Went Unknown";
trigger = {
platform = "state";
entity_id = "switch.someid";
to = "unknown";
for = "00:5:00";
};
action = {
service = "notify.notify";
data = {
message = "Object Went Offline";
};
};
}
Time Based Trigger, Setting Data Field On Entity Such as Thermostat
{
alias = "Do Something At Certain Time";
trigger = {
platform = "time";
at = "23:00:00";
};
action = {
service = "climate.set_temperature";
entity_id = "climate.thermostat";
data = {
temperature = "68";
};
};
}
If you did not create any automations through the UI, Home Assistant will fail loading because the automations.yaml
file does not exist yet and it will fail including it. To avoid that, add a systemd tmpfiles.d rule:
systemd.tmpfiles.rules = [
"f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
];
Trust a private certificate authority
Home Assistant does not natively support adding a private CA to the certificate store (see this thread for more details).
Home Assistant trusts certificates provided by the certifi python package, which nix overwrites with the cacert package. Using overrides you can append your root CA certificate to the certificates provided by certifi.
services.home-assistant.package = (pkgs.home-assistant.override {
extraPackages = py: with py; [ ];
packageOverrides = final: prev: {
certifi = prev.certifi.override {
cacert = pkgs.cacert.override {
extraCertificateFiles = [ ./my_custom_root_ca.crt ];
};
};
}).overrideAttrs (oldAttrs: {
doInstallCheck = false;
});
Example configurations
Misc
Run Home Assistant from GitHub repository
When developing Home Assistant for some test dependencies additional libraries are needed. A nix-shell expression for this is available here.