1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
{
lib,
callPackage,
python3Packages,
fetchFromGitHub,
installShellFiles,
platformio,
esptool,
git,
inetutils,
stdenv,
nixosTests,
}:
let
python = python3Packages.python.override {
self = python;
packageOverrides = self: super: {
esphome-dashboard = self.callPackage ./dashboard.nix { };
};
};
in
python.pkgs.buildPythonApplication rec {
pname = "esphome";
version = "2025.4.0";
pyproject = true;
src = fetchFromGitHub {
owner = pname;
repo = pname;
tag = version;
hash = "sha256-qK/vQQdgtYrWUglVaBWDcTbgeDUrDB4rpQ+4q65Hre4=";
};
build-systems = with python.pkgs; [
setuptools
argcomplete
];
nativeBuildInputs = [
installShellFiles
];
pythonRelaxDeps = true;
pythonRemoveDeps = [
"esptool"
"platformio"
];
postPatch = ''
substituteInPlace pyproject.toml \
--replace-fail "setuptools==" "setuptools>="
# ensure component dependencies are available
cat requirements_optional.txt >> requirements.txt
'';
# Remove esptool and platformio from requirements
env.ESPHOME_USE_SUBPROCESS = "";
# esphome has optional dependencies it does not declare, they are
# loaded when certain config blocks are used.
# They have validation functions like:
# - validate_cryptography_installed for the wifi component
dependencies = with python.pkgs; [
aioesphomeapi
argcomplete
cairosvg
click
colorama
cryptography
esphome-dashboard
esphome-glyphsets
freetype-py
icmplib
kconfiglib
packaging
paho-mqtt
pillow
platformio
protobuf
puremagic
pyparsing
pyserial
pyyaml
requests
ruamel-yaml
tornado
tzdata
tzlocal
voluptuous
];
makeWrapperArgs = [
# platformio is used in esphome/platformio_api.py
# esptool is used in esphome/__main__.py
# git is used in esphome/writer.py
# inetutils is used in esphome/dashboard/status/ping.py
"--prefix PATH : ${
lib.makeBinPath [
platformio
esptool
git
inetutils
]
}"
"--prefix PYTHONPATH : ${python.pkgs.makePythonPath dependencies}" # will show better error messages
"--prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ stdenv.cc.cc ]}"
"--set ESPHOME_USE_SUBPROCESS ''"
# https://github.com/NixOS/nixpkgs/issues/362193
"--set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION 'python'"
];
# Needed for tests
__darwinAllowLocalNetworking = true;
nativeCheckInputs = with python3Packages; [
hypothesis
mock
pytest-asyncio
pytest-cov-stub
pytest-mock
pytestCheckHook
];
disabledTests = [
# race condition, also visible in upstream tests
# tests/dashboard/test_web_server.py:78: IndexError
"test_devices_page"
];
postCheck = ''
$out/bin/esphome --help > /dev/null
'';
postInstall =
let
argcomplete = lib.getExe' python3Packages.argcomplete "register-python-argcomplete";
in
''
installShellCompletion --cmd esphome \
--bash <(${argcomplete} --shell bash esphome) \
--zsh <(${argcomplete} --shell zsh esphome) \
--fish <(${argcomplete} --shell fish esphome)
'';
passthru = {
dashboard = python.pkgs.esphome-dashboard;
updateScript = callPackage ./update.nix { };
tests = { inherit (nixosTests) esphome; };
};
meta = with lib; {
changelog = "https://github.com/esphome/esphome/releases/tag/${version}";
description = "Make creating custom firmwares for ESP32/ESP8266 super easy";
homepage = "https://esphome.io/";
license = with licenses; [
mit # The C++/runtime codebase of the ESPHome project (file extensions .c, .cpp, .h, .hpp, .tcc, .ino)
gpl3Only # The python codebase and all other parts of this codebase
];
maintainers = with maintainers; [
globin
hexa
];
mainProgram = "esphome";
};
}
|