mirror of
https://github.com/ilyakooo0/nixpkgs.git
synced 2024-11-10 16:45:51 +03:00
Merge pull request #160346 from mweinelt/hass-custom-everything
home-assistant: custom components and lovelace modules
This commit is contained in:
commit
3536221702
@ -513,6 +513,8 @@ The module update takes care of the new config syntax and the data itself (user
|
||||
|
||||
- `services.bitcoind` now properly respects the `enable` option.
|
||||
|
||||
- The Home Assistant module now offers support for installing custom components and lovelace modules. Available at [`services.home-assistant.customComponents`](#opt-services.home-assistant.customComponents) and [`services.home-assistant.customLovelaceModules`](#opt-services.home-assistant.customLovelaceModules).
|
||||
|
||||
## Nixpkgs internals {#sec-release-23.11-nixpkgs-internals}
|
||||
|
||||
- The use of `sourceRoot = "source";`, `sourceRoot = "source/subdir";`, and similar lines in package derivations using the default `unpackPhase` is deprecated as it requires `unpackPhase` to always produce a directory named "source". Use `sourceRoot = src.name`, `sourceRoot = "${src.name}/subdir";`, or `setSourceRoot = "sourceRoot=$(echo */subdir)";` or similar instead.
|
||||
|
@ -16,7 +16,8 @@ let
|
||||
cp ${format.generate "configuration.yaml" filteredConfig} $out
|
||||
sed -i -e "s/'\!\([a-z_]\+\) \(.*\)'/\!\1 \2/;s/^\!\!/\!/;" $out
|
||||
'';
|
||||
lovelaceConfig = cfg.lovelaceConfig or {};
|
||||
lovelaceConfig = if (cfg.lovelaceConfig == null) then {}
|
||||
else (lib.recursiveUpdate customLovelaceModulesResources cfg.lovelaceConfig);
|
||||
lovelaceConfigFile = format.generate "ui-lovelace.yaml" lovelaceConfig;
|
||||
|
||||
# Components advertised by the home-assistant package
|
||||
@ -62,8 +63,24 @@ let
|
||||
# Respect overrides that already exist in the passed package and
|
||||
# concat it with values passed via the module.
|
||||
extraComponents = oldArgs.extraComponents or [] ++ extraComponents;
|
||||
extraPackages = ps: (oldArgs.extraPackages or (_: []) ps) ++ (cfg.extraPackages ps);
|
||||
extraPackages = ps: (oldArgs.extraPackages or (_: []) ps)
|
||||
++ (cfg.extraPackages ps)
|
||||
++ (lib.concatMap (component: component.propagatedBuildInputs or []) cfg.customComponents);
|
||||
}));
|
||||
|
||||
# Create a directory that holds all lovelace modules
|
||||
customLovelaceModulesDir = pkgs.buildEnv {
|
||||
name = "home-assistant-custom-lovelace-modules";
|
||||
paths = cfg.customLovelaceModules;
|
||||
};
|
||||
|
||||
# Create parts of the lovelace config that reference lovelave modules as resources
|
||||
customLovelaceModulesResources = {
|
||||
lovelace.resources = map (card: {
|
||||
url = "/local/nixos-lovelace-modules/${card.entrypoint or card.pname}.js?${card.version}";
|
||||
type = "module";
|
||||
}) cfg.customLovelaceModules;
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
# Migrations in NixOS 22.05
|
||||
@ -137,6 +154,41 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
customComponents = mkOption {
|
||||
type = types.listOf types.package;
|
||||
default = [];
|
||||
example = literalExpression ''
|
||||
with pkgs.home-assistant-custom-components; [
|
||||
prometheus-sensor
|
||||
];
|
||||
'';
|
||||
description = lib.mdDoc ''
|
||||
List of custom component packages to install.
|
||||
|
||||
Available components can be found below `pkgs.home-assistant-custom-components`.
|
||||
'';
|
||||
};
|
||||
|
||||
customLovelaceModules = mkOption {
|
||||
type = types.listOf types.package;
|
||||
default = [];
|
||||
example = literalExpression ''
|
||||
with pkgs.home-assistant-custom-lovelace-modules; [
|
||||
mini-graph-card
|
||||
mini-media-player
|
||||
];
|
||||
'';
|
||||
description = lib.mdDoc ''
|
||||
List of custom lovelace card packages to load as lovelace resources.
|
||||
|
||||
Available cards can be found below `pkgs.home-assistant-custom-lovelace-modules`.
|
||||
|
||||
::: {.note}
|
||||
Automatic loading only works with lovelace in `yaml` mode.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
type = types.nullOr (types.submodule {
|
||||
freeformType = format.type;
|
||||
@ -408,9 +460,35 @@ in {
|
||||
rm -f "${cfg.configDir}/ui-lovelace.yaml"
|
||||
ln -s /etc/home-assistant/ui-lovelace.yaml "${cfg.configDir}/ui-lovelace.yaml"
|
||||
'';
|
||||
copyCustomLovelaceModules = if cfg.customLovelaceModules != [] then ''
|
||||
mkdir -p "${cfg.configDir}/www"
|
||||
ln -fns ${customLovelaceModulesDir} "${cfg.configDir}/www/nixos-lovelace-modules"
|
||||
'' else ''
|
||||
rm -f "${cfg.configDir}/www/nixos-lovelace-modules"
|
||||
'';
|
||||
copyCustomComponents = ''
|
||||
mkdir -p "${cfg.configDir}/custom_components"
|
||||
|
||||
# remove components symlinked in from below the /nix/store
|
||||
components="$(find "${cfg.configDir}/custom_components" -maxdepth 1 -type l)"
|
||||
for component in "$components"; do
|
||||
if [[ "$(readlink "$component")" =~ ^${escapeShellArg builtins.storeDir} ]]; then
|
||||
rm "$component"
|
||||
fi
|
||||
done
|
||||
|
||||
# recreate symlinks for desired components
|
||||
declare -a components=(${escapeShellArgs cfg.customComponents})
|
||||
for component in "''${components[@]}"; do
|
||||
path="$(dirname $(find "$component" -name "manifest.json"))"
|
||||
ln -fns "$path" "${cfg.configDir}/custom_components/"
|
||||
done
|
||||
'';
|
||||
in
|
||||
(optionalString (cfg.config != null) copyConfig) +
|
||||
(optionalString (cfg.lovelaceConfig != null) copyLovelaceConfig)
|
||||
(optionalString (cfg.lovelaceConfig != null) copyLovelaceConfig) +
|
||||
copyCustomLovelaceModules +
|
||||
copyCustomComponents
|
||||
;
|
||||
environment.PYTHONPATH = package.pythonPath;
|
||||
serviceConfig = let
|
||||
|
@ -43,6 +43,16 @@ in {
|
||||
psycopg2
|
||||
];
|
||||
|
||||
# test loading custom components
|
||||
customComponents = with pkgs.home-assistant-custom-components; [
|
||||
prometheus-sensor
|
||||
];
|
||||
|
||||
# test loading lovelace modules
|
||||
customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
|
||||
mini-graph-card
|
||||
];
|
||||
|
||||
config = {
|
||||
homeassistant = {
|
||||
name = "Home";
|
||||
@ -114,6 +124,14 @@ in {
|
||||
inheritParentConfig = true;
|
||||
configuration.services.home-assistant.config.backup = {};
|
||||
};
|
||||
|
||||
specialisation.removeCustomThings = {
|
||||
inheritParentConfig = true;
|
||||
configuration.services.home-assistant = {
|
||||
customComponents = lib.mkForce [];
|
||||
customLovelaceModules = lib.mkForce [];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes, ... }: let
|
||||
@ -161,6 +179,14 @@ in {
|
||||
hass.wait_for_open_port(8123)
|
||||
hass.succeed("curl --fail http://localhost:8123/lovelace")
|
||||
|
||||
with subtest("Check that custom components get installed"):
|
||||
hass.succeed("test -f ${configDir}/custom_components/prometheus_sensor/manifest.json")
|
||||
hass.wait_until_succeeds("journalctl -u home-assistant.service | grep -q 'We found a custom integration prometheus_sensor which has not been tested by Home Assistant'")
|
||||
|
||||
with subtest("Check that lovelace modules are referenced and fetchable"):
|
||||
hass.succeed("grep -q 'mini-graph-card-bundle.js' '${configDir}/ui-lovelace.yaml'")
|
||||
hass.succeed("curl --fail http://localhost:8123/local/nixos-lovelace-modules/mini-graph-card-bundle.js")
|
||||
|
||||
with subtest("Check that optional dependencies are in the PYTHONPATH"):
|
||||
env = get_unit_property("Environment")
|
||||
python_path = env.split("PYTHONPATH=")[1].split()[0]
|
||||
@ -200,6 +226,13 @@ in {
|
||||
for domain in ["backup"]:
|
||||
assert f"Setup of domain {domain} took" in journal, f"{domain} setup missing"
|
||||
|
||||
with subtest("Check custom components and custom lovelace modules get removed"):
|
||||
cursor = get_journal_cursor()
|
||||
hass.succeed("${system}/specialisation/removeCustomThings/bin/switch-to-configuration test")
|
||||
hass.fail("grep -q 'mini-graph-card-bundle.js' '${configDir}/ui-lovelace.yaml'")
|
||||
hass.fail("test -f ${configDir}/custom_components/prometheus_sensor/manifest.json")
|
||||
wait_for_homeassistant(cursor)
|
||||
|
||||
with subtest("Check that no errors were logged"):
|
||||
hass.fail("journalctl -u home-assistant -o cat | grep -q ERROR")
|
||||
|
||||
|
@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import importlib_metadata
|
||||
import sys
|
||||
|
||||
from packaging.requirements import Requirement
|
||||
|
||||
|
||||
def check_requirement(req: str):
|
||||
# https://packaging.pypa.io/en/stable/requirements.html
|
||||
requirement = Requirement(req)
|
||||
try:
|
||||
version = importlib_metadata.distribution(requirement.name).version
|
||||
except importlib_metadata.PackageNotFoundError:
|
||||
print(f" - Dependency {requirement.name} is missing", file=sys.stderr)
|
||||
return False
|
||||
|
||||
# https://packaging.pypa.io/en/stable/specifiers.html
|
||||
if not version in requirement.specifier:
|
||||
print(
|
||||
f" - {requirement.name}{requirement.specifier} expected, but got {version}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_manifest(manifest_file: str):
|
||||
with open(manifest_file) as fd:
|
||||
manifest = json.load(fd)
|
||||
if "requirements" in manifest:
|
||||
ok = True
|
||||
for requirement in manifest["requirements"]:
|
||||
ok &= check_requirement(requirement)
|
||||
if not ok:
|
||||
print("Manifest requirements are not met", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
raise RuntimeError(f"Usage {sys.argv[0]} <manifest>")
|
||||
manifest_file = sys.argv[1]
|
||||
check_manifest(manifest_file)
|
@ -0,0 +1,38 @@
|
||||
{ lib
|
||||
, home-assistant
|
||||
, makeSetupHook
|
||||
}:
|
||||
|
||||
{ pname
|
||||
, version
|
||||
, format ? "other"
|
||||
, ...
|
||||
}@args:
|
||||
|
||||
let
|
||||
manifestRequirementsCheckHook = import ./manifest-requirements-check-hook.nix {
|
||||
inherit makeSetupHook;
|
||||
inherit (home-assistant) python;
|
||||
};
|
||||
in
|
||||
home-assistant.python.pkgs.buildPythonPackage (
|
||||
{
|
||||
inherit format;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir $out
|
||||
cp -r $src/custom_components/ $out/
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
nativeCheckInputs = with home-assistant.python.pkgs; [
|
||||
importlib-metadata
|
||||
manifestRequirementsCheckHook
|
||||
packaging
|
||||
] ++ (args.nativeCheckInputs or []);
|
||||
|
||||
} // builtins.removeAttrs args [ "nativeCheckInputs" ]
|
||||
)
|
@ -0,0 +1,11 @@
|
||||
{ python
|
||||
, makeSetupHook
|
||||
}:
|
||||
|
||||
makeSetupHook {
|
||||
name = "manifest-requirements-check-hook";
|
||||
substitutions = {
|
||||
pythonCheckInterpreter = python.interpreter;
|
||||
checkManifest = ./check_manifest.py;
|
||||
};
|
||||
} ./manifest-requirements-check-hook.sh
|
@ -0,0 +1,25 @@
|
||||
# Setup hook to check HA manifest requirements
|
||||
echo "Sourcing manifest-requirements-check-hook"
|
||||
|
||||
function manifestCheckPhase() {
|
||||
echo "Executing manifestCheckPhase"
|
||||
runHook preCheck
|
||||
|
||||
manifests=$(shopt -s nullglob; echo $out/custom_components/*/manifest.json)
|
||||
|
||||
if [ ! -z "$manifests" ]; then
|
||||
echo Checking manifests $manifests
|
||||
@pythonCheckInterpreter@ @checkManifest@ $manifests
|
||||
else
|
||||
echo "No custom component manifests found in $out" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
runHook postCheck
|
||||
echo "Finished executing manifestCheckPhase"
|
||||
}
|
||||
|
||||
if [ -z "${dontCheckManifest-}" ] && [ -z "${installCheckPhase-}" ]; then
|
||||
echo "Using manifestCheckPhase"
|
||||
preDistPhases+=" manifestCheckPhase"
|
||||
fi
|
57
pkgs/servers/home-assistant/custom-components/README.md
Normal file
57
pkgs/servers/home-assistant/custom-components/README.md
Normal file
@ -0,0 +1,57 @@
|
||||
# Packaging guidelines
|
||||
|
||||
## buildHomeAssistantComponent
|
||||
|
||||
Custom components should be packaged using the
|
||||
`buildHomeAssistantComponent` function, that is provided at top-level.
|
||||
It builds upon `buildPythonPackage` but uses a custom install and check
|
||||
phase.
|
||||
|
||||
Python runtime dependencies can be directly consumed as unqualified
|
||||
function arguments. Pass them into `propagatedBuildInputs`, for them to
|
||||
be available to Home Assistant.
|
||||
|
||||
Out-of-tree components need to use python packages from
|
||||
`home-assistant.python.pkgs` as to not introduce conflicting package
|
||||
versions into the Python environment.
|
||||
|
||||
|
||||
**Example Boilerplate:**
|
||||
|
||||
```nix
|
||||
{ lib
|
||||
, buildHomeAssistantcomponent
|
||||
, fetchFromGitHub
|
||||
}:
|
||||
|
||||
buildHomeAssistantComponent {
|
||||
# pname, version
|
||||
|
||||
src = fetchFromGithub {
|
||||
# owner, repo, rev, hash
|
||||
};
|
||||
|
||||
propagatedBuildInputs = [
|
||||
# python requirements, as specified in manifest.json
|
||||
];
|
||||
|
||||
meta = with lib; {
|
||||
# changelog, description, homepage, license, maintainers
|
||||
}
|
||||
}
|
||||
|
||||
## Package name normalization
|
||||
|
||||
Apply the same normalization rules as defined for python packages in
|
||||
[PEP503](https://peps.python.org/pep-0503/#normalized-names).
|
||||
The name should be lowercased and dots, underlines or multiple
|
||||
dashes should all be replaced by a single dash.
|
||||
|
||||
## Manifest check
|
||||
|
||||
The `buildHomeAssistantComponent` builder uses a hook to check whether
|
||||
the dependencies specified in the `manifest.json` are present and
|
||||
inside the specified version range.
|
||||
|
||||
There shouldn't be a need to disable this hook, but you can set
|
||||
`dontCheckManifest` to `true` in the derivation to achieve that.
|
@ -0,0 +1,6 @@
|
||||
{ callPackage
|
||||
}:
|
||||
|
||||
{
|
||||
prometheus-sensor = callPackage ./prometheus-sensor {};
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
{ lib
|
||||
, fetchFromGitHub
|
||||
, buildHomeAssistantComponent
|
||||
}:
|
||||
|
||||
buildHomeAssistantComponent rec {
|
||||
pname = "prometheus-sensor";
|
||||
version = "1.0.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "mweinelt";
|
||||
repo = "ha-prometheus-sensor";
|
||||
rev = "refs/tags/${version}";
|
||||
hash = "sha256-10COLFXvmpm8ONLyx5c0yiQdtuP0SC2NKq/ZYHro9II=";
|
||||
};
|
||||
|
||||
dontBuild = true;
|
||||
|
||||
meta = with lib; {
|
||||
changelog = "https://github.com/mweinelt/ha-prometheus-sensor/blob/${version}/CHANGELOG.md";
|
||||
description = "Import prometheus query results into Home Assistant";
|
||||
homepage = "https://github.com/mweinelt/ha-prometheus-sensor";
|
||||
maintainers = with maintainers; [ hexa ];
|
||||
license = licenses.mit;
|
||||
};
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
# Packaging guidelines
|
||||
|
||||
## Entrypoint
|
||||
|
||||
Every lovelace module has an entrypoint in the form of a `.js` file. By
|
||||
default the nixos module will try to load `${pname}.js` when a module is
|
||||
configured.
|
||||
|
||||
The entrypoint used can be overridden in `passthru` like this:
|
||||
|
||||
```nix
|
||||
passthru.entrypoint = "demo-card-bundle.js";
|
||||
```
|
@ -0,0 +1,8 @@
|
||||
{ callPackage
|
||||
}:
|
||||
|
||||
{
|
||||
mini-graph-card = callPackage ./mini-graph-card {};
|
||||
|
||||
mini-media-player = callPackage ./mini-media-player {};
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
{ lib
|
||||
, buildNpmPackage
|
||||
, fetchFromGitHub
|
||||
}:
|
||||
|
||||
buildNpmPackage rec {
|
||||
pname = "mini-graph-card";
|
||||
version = "0.11.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "kalkih";
|
||||
repo = "mini-graph-card";
|
||||
rev = "refs/tags/v${version}";
|
||||
hash = "sha256-AC4VawRtWTeHbFqDJ6oQchvUu08b4F3ManiPPXpyGPc=";
|
||||
};
|
||||
|
||||
npmDepsHash = "sha256-0ErOTkcCnMqMTsTkVL320SxZaET/izFj9GiNWC2tQtQ=";
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir $out
|
||||
cp -v dist/mini-graph-card-bundle.js $out/
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
passthru.entrypoint = "mini-graph-card-bundle.js";
|
||||
|
||||
meta = with lib; {
|
||||
changelog = "https://github.com/kalkih/mini-graph-card/releases/tag/v${version}";
|
||||
description = "Minimalistic graph card for Home Assistant Lovelace UI";
|
||||
homepage = "https://github.com/kalkih/mini-graph-card";
|
||||
maintainers = with maintainers; [ hexa ];
|
||||
license = licenses.mit;
|
||||
};
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
{ lib
|
||||
, buildNpmPackage
|
||||
, fetchFromGitHub
|
||||
}:
|
||||
|
||||
buildNpmPackage rec {
|
||||
pname = "mini-media-player";
|
||||
version = "1.16.5";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "kalkih";
|
||||
repo = "mini-media-player";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-ydkY7Qx2GMh4CpvvBAQubJ7PlxSscDZRJayn82bOczM=";
|
||||
};
|
||||
|
||||
npmDepsHash = "sha256-v9NvZOrQPMOoG3LKACnu79jKgZtcnGiopWad+dFbplw=";
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir $out
|
||||
cp -v ./dist/mini-media-player-bundle.js $out/
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
passthru.entrypoint = "mini-media-player-bundle.js";
|
||||
|
||||
meta = with lib; {
|
||||
changelog = "https://github.com/kalkih/mini-media-player/releases/tag/v${version}";
|
||||
description = "Minimalistic media card for Home Assistant Lovelace UI";
|
||||
homepage = "https://github.com/kalkih/mini-media-player";
|
||||
license = licenses.mit;
|
||||
maintainers = with maintainers; [ hexa ];
|
||||
};
|
||||
}
|
@ -393,6 +393,10 @@ in python.pkgs.buildPythonApplication rec {
|
||||
|
||||
# leave this in, so users don't have to constantly update their downstream patch handling
|
||||
patches = [
|
||||
# Follow symlinks in /var/lib/hass/www
|
||||
./patches/static-symlinks.patch
|
||||
|
||||
# Patch path to ffmpeg binary
|
||||
(substituteAll {
|
||||
src = ./patches/ffmpeg-path.patch;
|
||||
ffmpeg = "${lib.getBin ffmpeg-headless}/bin/ffmpeg";
|
||||
|
37
pkgs/servers/home-assistant/patches/static-symlinks.patch
Normal file
37
pkgs/servers/home-assistant/patches/static-symlinks.patch
Normal file
@ -0,0 +1,37 @@
|
||||
diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py
|
||||
index 2ec991750f..9a937006ce 100644
|
||||
--- a/homeassistant/components/frontend/__init__.py
|
||||
+++ b/homeassistant/components/frontend/__init__.py
|
||||
@@ -383,7 +383,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
|
||||
local = hass.config.path("www")
|
||||
if os.path.isdir(local):
|
||||
- hass.http.register_static_path("/local", local, not is_dev)
|
||||
+ hass.http.register_static_path("/local", local, not is_dev, follow_symlinks=True)
|
||||
|
||||
# Can be removed in 2023
|
||||
hass.http.register_redirect("/config/server_control", "/developer-tools/yaml")
|
||||
diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py
|
||||
index 122b7b79ce..3cf2b7e0db 100644
|
||||
--- a/homeassistant/components/http/__init__.py
|
||||
+++ b/homeassistant/components/http/__init__.py
|
||||
@@ -411,16 +411,16 @@ class HomeAssistantHTTP:
|
||||
)
|
||||
|
||||
def register_static_path(
|
||||
- self, url_path: str, path: str, cache_headers: bool = True
|
||||
+ self, url_path: str, path: str, cache_headers: bool = True, follow_symlinks: bool = False
|
||||
) -> None:
|
||||
"""Register a folder or file to serve as a static path."""
|
||||
if os.path.isdir(path):
|
||||
if cache_headers:
|
||||
resource: CachingStaticResource | web.StaticResource = (
|
||||
- CachingStaticResource(url_path, path)
|
||||
+ CachingStaticResource(url_path, path, follow_symlinks=follow_symlinks)
|
||||
)
|
||||
else:
|
||||
- resource = web.StaticResource(url_path, path)
|
||||
+ resource = web.StaticResource(url_path, path, follow_symlinks=follow_symlinks)
|
||||
self.app.router.register_resource(resource)
|
||||
self.app["allow_configured_cors"](resource)
|
||||
return
|
@ -26472,6 +26472,14 @@ with pkgs;
|
||||
|
||||
home-assistant = callPackage ../servers/home-assistant { };
|
||||
|
||||
buildHomeAssistantComponent = callPackage ../servers/home-assistant/build-custom-component { };
|
||||
home-assistant-custom-components = lib.recurseIntoAttrs
|
||||
(callPackage ../servers/home-assistant/custom-components {
|
||||
inherit (home-assistant.python.pkgs) callPackage;
|
||||
});
|
||||
home-assistant-custom-lovelace-modules = lib.recurseIntoAttrs
|
||||
(callPackage ../servers/home-assistant/custom-lovelace-modules {});
|
||||
|
||||
home-assistant-cli = callPackage ../servers/home-assistant/cli.nix { };
|
||||
|
||||
home-assistant-component-tests = recurseIntoAttrs home-assistant.tests.components;
|
||||
|
Loading…
Reference in New Issue
Block a user