14 # Look up dependencies of specified components in component-packages.nix
15 , extraComponents ? [ ]
17 # Additional packages to add to propagatedBuildInputs
18 , extraPackages ? ps: []
20 # Override Python packages using
21 # self: super: { pkg = super.pkg.overridePythonAttrs (oldAttrs: { ... }); }
22 # Applied after defaultOverrides
23 , packageOverrides ? self: super: {}
25 # Skip pip install of required packages on startup
30 # Override the version of some packages pinned in Home Assistant's setup.py and requirements_all.txt
33 aioelectricitymaps = super.aioelectricitymaps.overridePythonAttrs (oldAttrs: rec {
35 src = fetchFromGitHub {
37 repo = "aioelectricitymaps";
38 rev = "refs/tags/v${version}";
39 hash = "sha256-q06B40c0uvSuzH/3YCoxg4p9aNIOPrphsoESktF+B14=";
41 nativeCheckInputs = with self; [
46 aiopurpleair = super.aiopurpleair.overridePythonAttrs (oldAttrs: rec {
47 version = "2022.12.1";
48 src = fetchFromGitHub {
50 repo = "aiopurpleair";
51 rev = "refs/tags/${version}";
52 hash = "sha256-YmJH4brWkTpgzyHwu9UnIWrY5qlDCmMtvF+KxQFXwfk=";
55 substituteInPlace pyproject.toml --replace-fail \
56 '"setuptools >= 35.0.2", "wheel >= 0.29.0", "poetry>=0.12"' \
61 aioskybell = super.aioskybell.overridePythonAttrs (oldAttrs: rec {
63 src = fetchFromGitHub {
66 rev = "refs/tags/${version}";
67 hash = "sha256-aBT1fDFtq1vasTvCnAXKV2vmZ6LBLZqRCiepv1HDJ+Q=";
71 aiowatttime = super.aiowatttime.overridePythonAttrs (oldAttrs: rec {
73 src = fetchFromGitHub {
76 rev = "refs/tags/${version}";
77 hash = "sha256-tWnxGLJT+CRFvkhxFamHxnLXBvoR8tfOvzH1o1i5JJg=";
80 substituteInPlace pyproject.toml --replace-fail \
81 '"setuptools >= 35.0.2", "wheel >= 0.29.0", "poetry>=0.12"' \
86 astral = super.astral.overridePythonAttrs (oldAttrs: rec {
90 inherit pname version;
91 hash = "sha256-5B2ZZ9XEi+QhNGVS8PTe2tQ/85qDV09f8q0ytmJ7b74=";
94 substituteInPlace pyproject.toml \
95 --replace-fail "poetry>=1.0.0b1" "poetry-core" \
96 --replace-fail "poetry.masonry" "poetry.core.masonry"
98 propagatedBuildInputs = (oldAttrs.propagatedBuildInputs or []) ++ [
103 gspread = super.gspread.overridePythonAttrs (oldAttrs: rec {
105 src = fetchFromGitHub {
108 rev = "refs/tags/v${version}";
109 hash = "sha256-i+QbnF0Y/kUMvt91Wzb8wseO/1rZn9xzeA5BWg1haks=";
111 dependencies = with self; [
116 inline-snapshot = super.inline-snapshot.overridePythonAttrs (oldAttrs: {
117 disabledTests = oldAttrs.disabledTests or [ ] ++ [
118 # fixture does not expect pydantic<2
123 openhomedevice = super.openhomedevice.overridePythonAttrs (oldAttrs: rec {
125 src = fetchFromGitHub {
126 inherit (oldAttrs.src) owner repo;
127 rev = "refs/tags/${version}";
128 hash = "sha256-GGp7nKFH01m1KW6yMkKlAdd26bDi8JDWva6OQ0CWMIw=";
132 pymelcloud = super.pymelcloud.overridePythonAttrs (oldAttrs: {
134 src = fetchFromGitHub {
135 owner = "vilppuvuorinen";
137 rev = "33a827b6cd0b34f276790faa49bfd0994bb7c2e4"; # 2.5.x branch
138 sha256 = "sha256-Q3FIo9YJwtWPHfukEBjBANUQ1N1vr/DMnl1dgiN7vYg=";
142 notifications-android-tv = super.notifications-android-tv.overridePythonAttrs (oldAttrs: rec {
144 format = "setuptools";
146 src = fetchFromGitHub {
148 repo = "notifications_android_tv";
149 rev = "refs/tags/${version}";
150 hash = "sha256-adkcUuPl0jdJjkBINCTW4Kmc16C/HzL+jaRZB/Qr09A=";
153 nativeBuildInputs = with self; [
157 propagatedBuildInputs = with self; [
161 doCheck = false; # no tests
164 plugwise = super.plugwise.overridePythonAttrs (oldAttrs: rec {
166 src = fetchFromGitHub {
167 inherit (oldAttrs.src) owner repo;
168 rev = "refs/tags/v${version}";
169 hash = "sha256-dlDytOSp/7npanxXH5uaDv29AP21UciEzIzDlMf6jf8=";
173 # Pinned due to API changes in 0.1.0
174 poolsense = super.poolsense.overridePythonAttrs (oldAttrs: rec {
179 hash = "sha256-17MHrYRmqkH+1QLtgq2d6zaRtqvb9ju9dvPt9gB2xCc=";
183 # Pinned due to API changes >0.3.5.3
184 pyatag = super.pyatag.overridePythonAttrs (oldAttrs: rec {
186 src = fetchFromGitHub {
190 sha256 = "00ly4injmgrj34p0lyx7cz2crgnfcijmzc0540gf7hpwha0marf6";
194 pyaussiebb = super.pyaussiebb.overridePythonAttrs (oldAttrs: rec {
196 src = fetchFromGitHub {
199 rev = "refs/tags/v${version}";
200 hash = "sha256-tEdddVsLFCHRvyLCctDakioiop2xWaJlfGE16P1ukHc=";
204 pydantic = super.pydantic_1;
206 pydexcom = super.pydexcom.overridePythonAttrs (oldAttrs: rec {
208 src = fetchFromGitHub {
211 rev = "refs/tags/${version}";
212 hash = "sha256-ItDGnUUUTwCz4ZJtFVlMYjjoBPn2h8QZgLzgnV2T/Qk=";
216 pyflume = super.pyflume.overridePythonAttrs (oldAttrs: rec {
218 src = fetchFromGitHub {
219 owner = "ChrisMandich";
221 rev = "refs/tags/v${version}";
222 hash = "sha256-kIE3y/qlsO9Y1MjEQcX0pfaBeIzCCHk4f1Xa215BBHo=";
224 dependencies = oldAttrs.propagatedBuildInputs or [] ++ [
229 pykaleidescape = super.pykaleidescape.overridePythonAttrs (oldAttrs: rec {
231 src = fetchFromGitHub {
232 inherit (oldAttrs.src) owner repo;
233 rev = "refs/tags/v${version}";
234 hash = "sha256-KM/gtpsQ27QZz2uI1t/yVN5no0zp9LZag1duAJzK55g=";
238 pymodbus = super.pymodbus.overridePythonAttrs (oldAttrs: rec {
240 src = fetchFromGitHub {
241 inherit (oldAttrs.src) owner repo;
242 rev = "refs/tags/v${version}";
243 hash = "sha256-ScqxDO0hif8p3C6+vvm7FgSEQjCXBwUPOc7Y/3OfkoI=";
247 pyoctoprintapi = super.pyoctoprintapi.overridePythonAttrs (oldAttrs: rec {
249 src = fetchFromGitHub {
250 owner = "rfleming71";
251 repo = "pyoctoprintapi";
252 rev = "refs/tags/v${version}";
253 hash = "sha256-Jf/zYnBHVl3TYxFy9Chy6qNH/eCroZkmUOEWfd62RIo=";
257 pysnooz = super.pysnooz.overridePythonAttrs (oldAttrs: rec {
259 src = fetchFromGitHub {
260 owner = "AustinBrunkhorst";
262 rev = "refs/tags/v${version}";
263 hash = "sha256-hJwIObiuFEAVhgZXYB9VCeAlewBBnk0oMkP83MUCpyU=";
267 # newer versions require pydantic>=2
268 python-on-whales = super.python-on-whales.overridePythonAttrs (oldAttrs: rec {
270 src = fetchFromGitHub {
271 inherit (oldAttrs.src) owner repo;
272 rev = "refs/tags/v${version}";
273 hash = "sha256-oKI7zXfoUVmJXLQvyoDEmoCL4AwaYgaFcLKNlFFrC9o=";
277 pytradfri = super.pytradfri.overridePythonAttrs (oldAttrs: rec {
279 src = fetchFromGitHub {
280 owner = "home-assistant-libs";
282 rev = "refs/tags/${version}";
283 hash = "sha256-xOdTzG0bF5p1QpkXv2btwrVugQRjSwdAj8bXcC0IoQg=";
287 # newer sigstore version transitivevly require pydantic>=2
288 sigstore = super.sigstore.overridePythonAttrs (oldAttrs: rec {
290 src = fetchFromGitHub {
292 repo = "sigstore-python";
293 rev = "refs/tags/v${version}";
294 hash = "sha256-QqY5GOBS75OkbSaF5Ua5jnJAhsYfVRuWLUoWDxX8Ino=";
296 dependencies = with self; [
305 sigstore-protobuf-specs
308 doCheck = false; # pytest too new
311 sigstore-protobuf-specs = super.sigstore-protobuf-specs.overridePythonAttrs {
314 pname = "sigstore-protobuf-specs";
316 hash = "sha256-YistIxYToo7T5mYKzYeBhnW06DSG9JoPDBmKxUdfy4E=";
318 nativeBuildInputs = with self; [
326 slack-sdk = super.slack-sdk.overridePythonAttrs (oldAttrs: rec {
328 src = fetchFromGitHub {
330 repo = "python-slackclient";
331 rev = "refs/tags/${version}";
332 hash = "sha256-U//HUe6e41wOOzoaDl4yXPnEASCzpGBIScHStWMN8tk=";
335 substituteInPlace setup.py \
336 --replace-fail "pytest-runner" ""
338 pythonImportsCheck = [ "slack" ];
339 doCheck = false; # Tests changed a lot for > 3
342 # pinned for sigstore
343 tuf = super.tuf.overridePythonAttrs rec {
345 src = fetchFromGitHub {
346 owner = "theupdateframework";
348 rev = "refs/tags/v${version}";
349 hash = "sha256-MdPctAZuKn/YAwpMJ5gWU7PXJD3iK7bYprLXV52wNQQ=";
356 voip-utils = super.voip-utils.overridePythonAttrs (oldAttrs: rec {
358 src = fetchFromGitHub {
359 inherit (oldAttrs.src) owner repo;
360 rev = "refs/tags/v${version}";
361 hash = "sha256-PG4L6KphH9JIZO76cCN8eClFE2CneEIExlXS+x79k3U=";
365 vulcan-api = super.vulcan-api.overridePythonAttrs (oldAttrs: rec {
367 src = fetchFromGitHub {
368 inherit (oldAttrs.src) owner repo;
369 rev = "refs/tags/v${version}";
370 hash = "sha256-ebWKcRxAAkHVqV2RaftIHBRJe/TYSUxS+5Utxb0yhtw=";
374 # Pinned due to API changes ~1.0
375 vultr = super.vultr.overridePythonAttrs (oldAttrs: rec {
377 src = fetchFromGitHub {
378 owner = "spry-group";
379 repo = "python-vultr";
381 hash = "sha256-sHCZ8Csxs5rwg1ZG++hP3MfK7ldeAdqm5ta9tEXeW+I=";
385 xbox-webapi = super.xbox-webapi.overridePythonAttrs (oldAttrs: rec {
387 src = fetchFromGitHub {
389 repo = "xbox-webapi-python";
390 rev = "refs/tags/v${version}";
391 hash = "sha256-fzMB+I8+ZTJUiZovcuj+d5GdHY9BJyJd6j92EhJeIFI=";
394 sed -i '/pytest-runner/d' setup.py
396 propagatedBuildInputs = with self; [
403 nativeCheckInputs = with self; [
408 youtubeaio = super.youtubeaio.overridePythonAttrs (old: {
410 # fails with pydantic v1
411 "--deselect=tests/test_video.py::test_fetch_video"
415 # internal python packages only consumed by home-assistant itself
416 home-assistant-frontend = self.callPackage ./frontend.nix { };
417 home-assistant-intents = self.callPackage ./intents.nix { };
418 homeassistant = self.toPythonModule home-assistant;
419 pytest-homeassistant-custom-component = self.callPackage ./pytest-homeassistant-custom-component.nix { };
423 python = python312.override {
425 packageOverrides = lib.composeManyExtensions (defaultOverrides ++ [ packageOverrides ]);
428 componentPackages = import ./component-packages.nix;
430 availableComponents = builtins.attrNames componentPackages.components;
432 inherit (componentPackages) supportedComponentsWithTests;
434 getPackages = component: componentPackages.components.${component};
436 componentBuildInputs = lib.concatMap (component: getPackages component python.pkgs) extraComponents;
438 # Ensure that we are using a consistent package set
439 extraBuildInputs = extraPackages python.pkgs;
441 # Don't forget to run update-component-packages.py after updating
442 hassVersion = "2024.11.3";
444 in python.pkgs.buildPythonApplication rec {
445 pname = "homeassistant";
446 version = assert (componentPackages.version == hassVersion); hassVersion;
449 # check REQUIRED_PYTHON_VER in homeassistant/const.py
450 disabled = python.pythonOlder "3.11";
452 # don't try and fail to strip 6600+ python files, it takes minutes!
455 # Primary source is the git, which has the tests and allows bisecting the core
456 src = fetchFromGitHub {
457 owner = "home-assistant";
459 rev = "refs/tags/${version}";
460 hash = "sha256-9b4HPSCPYUUwKxn0JBw5uN6nI97jvgqBHFRUNhDue/k=";
463 # Secondary source is pypi sdist for translations
465 inherit pname version;
466 hash = "sha256-W7Z6C3kMyEIkY/3zQHm1OMMN7Tuj3ThsubLo6KjVotw=";
469 build-system = with python.pkgs; [
495 # extract translations from pypi sdist
497 tar --extract --gzip --file $sdist --strip-components 1 --wildcards "**/translations"
500 # leave this in, so users don't have to constantly update their downstream patch handling
502 # Follow symlinks in /var/lib/hass/www
503 ./patches/static-follow-symlinks.patch
505 # Patch path to ffmpeg binary
507 src = ./patches/ffmpeg-path.patch;
508 ffmpeg = "${lib.getExe ffmpeg-headless}";
513 substituteInPlace tests/test_core_config.py --replace-fail '"/usr"' "\"$NIX_BUILD_TOP/media\""
515 sed -i 's/setuptools[~=]/setuptools>/' pyproject.toml
518 dependencies = with python.pkgs; [
519 # Only packages required in pyproject.toml
528 atomicwrites-homeassistant
537 home-assistant-bluetooth
546 psutil-home-assistant
561 # REQUIREMENTS in homeassistant/auth/mfa_modules/totp.py and homeassistant/auth/mfa_modules/notify.py
566 makeWrapperArgs = lib.optional skipPip "--add-flags --skip-pip";
568 # upstream only tests on Linux, so do we.
569 doCheck = stdenv.hostPlatform.isLinux;
571 nativeCheckInputs = with python.pkgs; [
572 # test infrastructure (selectively from requirement_test.txt)
588 # Sneakily imported in tests/conftest.py
590 # Used in tests/non_packaged_scripts/test_alexa_locales.py
592 ] ++ lib.concatMap (component: getPackages component python.pkgs) [
593 # some components are needed even if tests in tests/components are disabled
599 # assign tests grouped by file to workers
601 # retry racy tests that end in "RuntimeError: Event loop is closed"
603 "--only-rerun RuntimeError"
604 # enable full variable printing on error
606 # AssertionError: assert 1 == 0
607 "--deselect tests/test_config.py::test_merge"
608 # AssertionError: assert 6 == 5
609 "--deselect=tests/helpers/test_translation.py::test_caching"
610 # assert "Detected that integration 'hue' attempted to create an asyncio task from a thread at homeassistant/components/hue/light.py, line 23
611 "--deselect=tests/util/test_async.py::test_create_eager_task_from_thread_in_integration"
612 # Services were renamed to Actions in language strings, but the tests are lagging behind
613 "--deselect=tests/test_core.py::test_serviceregistry_service_that_not_exists"
614 "--deselect=tests/test_core.py::test_services_call_return_response_requires_blocking"
615 "--deselect=tests/test_core.py::test_serviceregistry_return_response_arguments"
616 "--deselect=tests/helpers/test_script.py::test_parallel_error"
617 "--deselect=tests/helpers/test_script.py::test_propagate_error_service_not_found"
618 "--deselect=tests/helpers/test_script.py::test_continue_on_error_automation_issue"
619 # checks whether pip is installed
620 "--deselect=tests/util/test_package.py::test_check_package_fragment"
621 # tests are located in tests/
625 disabledTestPaths = [
626 # we neither run nor distribute hassfest
628 # we don't care about code quality
630 # redundant component import test, which would make debugpy & sentry expensive to review
631 "tests/test_circular_imports.py"
632 # don't bulk test all components
637 export HOME="$TEMPDIR"
639 # the tests require the existance of a media dir
640 mkdir "$NIX_BUILD_TOP"/media
642 # put ping binary into PATH, e.g. for wake_on_lan tests
643 export PATH=${inetutils}/bin:$PATH
652 supportedComponentsWithTests;
653 pythonPath = python.pkgs.makePythonPath (componentBuildInputs ++ extraBuildInputs);
654 frontend = python.pkgs.home-assistant-frontend;
655 intents = python.pkgs.home-assistant-intents;
657 nixos = nixosTests.home-assistant;
658 components = callPackage ./tests.nix { };
659 version = testers.testVersion {
660 package = home-assistant;
661 command = "hass --version";
663 withoutCheckDeps = home-assistant.overridePythonAttrs {
664 pname = "home-assistant-without-check-deps";
671 homepage = "https://home-assistant.io/";
672 description = "Open source home automation that puts local control and privacy first";
673 license = licenses.asl20;
674 maintainers = teams.home-assistant.members;
675 platforms = platforms.linux;
676 mainProgram = "hass";