me like nix
1{
2 pkgs,
3 config,
4 ...
5}:
6
7{
8 imports = [
9 # Include the results of the hardware scan.
10 ./hardware-configuration.nix
11 ../common/common.nix
12 ];
13
14 networking.hostName = "mira"; # Define your hostname.
15 # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
16
17 # Configure network proxy if necessary
18 # networking.proxy.default = "http://user:password@proxy:port/";
19 # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
20
21 # this is like a network devices discovery thing
22 services.avahi = {
23 enable = true;
24 nssmdns4 = true;
25 openFirewall = true;
26 };
27
28 services.copyparty.enable = true;
29
30 services.openssh = {
31 enable = true;
32 settings = {
33 PasswordAuthentication = false;
34 KbdInteractiveAuthentication = false;
35 PermitRootLogin = "no";
36 AllowUsers = [ "sean" ];
37 };
38 };
39
40 users.users.sean.openssh.authorizedKeys.keys = [
41 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc="
42 ];
43
44 # List services that you want to enable:
45 services.flaresolverr.enable = true;
46 nixarr = {
47 enable = true;
48 mediaDir = "/mnt/storage1/nixarr/media";
49 vpn = {
50 enable = true;
51 wgConf = "/mnt/storage1/nixarr/wireguard.conf";
52 };
53
54 jellyfin = {
55 enable = true;
56 openFirewall = true;
57 };
58
59 transmission = {
60 enable = true;
61 vpn.enable = true;
62 };
63 sabnzbd = {
64 enable = true;
65 vpn.enable = true;
66 openFirewall = true;
67 };
68
69 prowlarr.enable = true;
70 radarr.enable = true;
71 sonarr.enable = true;
72 jellyseerr = {
73 enable = true;
74 openFirewall = true;
75 };
76
77 recyclarr = {
78 enable = true;
79 configuration = {
80 sonarr = {
81 series = {
82 base_url = "http://localhost:8989";
83 api_key = "!env_var SONARR_API_KEY";
84 quality_definition = {
85 type = "series";
86 };
87 delete_old_custom_formats = true;
88 custom_formats = [
89 {
90 trash_ids = [
91 "85c61753df5da1fb2aab6f2a47426b09" # BR-DISK
92 "9c11cd3f07101cdba90a2d81cf0e56b4" # LQ
93 ];
94 assign_scores_to = [
95 {
96 name = "WEB-DL (1080p)";
97 score = -10000;
98 }
99 ];
100 }
101 ];
102 };
103 };
104 radarr = {
105 movies = {
106 base_url = "http://localhost:7878";
107 api_key = "!env_var RADARR_API_KEY";
108 quality_definition = {
109 type = "movie";
110 };
111 delete_old_custom_formats = true;
112 custom_formats = [
113 {
114 trash_ids = [
115 "570bc9ebecd92723d2d21500f4be314c" # Remaster
116 "eca37840c13c6ef2dd0262b141a5482f" # 4K Remaster
117 ];
118 assign_scores_to = [
119 {
120 name = "HD Bluray + WEB";
121 score = 25;
122 }
123 ];
124 }
125 ];
126 };
127 };
128 };
129 };
130 };
131
132 # MQTT broker for Home Assistant (Tasmota devices, Frigate)
133 services.mosquitto = {
134 enable = true;
135 listeners = [
136 {
137 acl = [ "pattern readwrite #" ];
138 omitPasswordAuth = true;
139 settings.allow_anonymous = true;
140 }
141 ];
142 };
143
144 # Frigate NVR for camera recording and AI object detection
145 services.frigate = {
146 enable = true;
147 hostname = "frigate";
148 settings = {
149 mqtt = {
150 enabled = true;
151 host = "localhost";
152 port = 1883;
153 };
154
155 # Detector configuration - CPU for now (can add GPU later)
156 detectors = {
157 cpu = {
158 type = "cpu";
159 num_threads = 4;
160 };
161 };
162
163 # Camera configuration - Pi Camera via go2rtc
164 cameras = {
165 picam = {
166 enabled = true;
167 ffmpeg = {
168 inputs = [
169 {
170 path = "rtsp://pi:8554/picam";
171 roles = [ "detect" "record" ];
172 }
173 ];
174 };
175 detect = {
176 enabled = true;
177 width = 1920;
178 height = 1080;
179 fps = 5; # Lower FPS for detection to reduce CPU
180 };
181 record = {
182 enabled = true;
183 retain = {
184 days = 7;
185 mode = "active_objects";
186 };
187 };
188 snapshots = {
189 enabled = true;
190 bounding_box = true;
191 retain = {
192 default = 14;
193 };
194 };
195 objects = {
196 track = [ "person" "dog" "cat" "car" ];
197 };
198 };
199 };
200
201 # Recording storage
202 record = {
203 enabled = true;
204 retain = {
205 days = 7;
206 mode = "active_objects";
207 };
208 };
209 };
210 };
211
212 # Home Assistant service
213 services.home-assistant = {
214 enable = true;
215 customComponents = with pkgs.home-assistant-custom-components; [
216 frigate
217 ];
218 extraComponents = [
219 "esphome"
220 "met"
221 "radio_browser"
222 "homekit"
223 "homekit_controller"
224 "isal"
225 "mqtt"
226 "tasmota"
227 "wiz"
228 "google_translate" # TTS - was missing gtts module
229 "ecobee" # Was missing pyecobee module
230 "ibeacon" # Was missing ibeacon_ble module
231 "go2rtc" # Camera streaming
232 "generic" # Generic camera integration
233 ];
234 config = {
235 homeassistant = {
236 time_zone = "America/Toronto";
237 };
238 default_config = { };
239 zeroconf = { };
240 # MQTT configuration - broker must be set up via UI
241 mqtt = { };
242 # Automations
243 automation = [
244 {
245 id = "1761448856909";
246 alias = "Lower heat at night";
247 trigger = [
248 {
249 platform = "time";
250 at = "23:00:00";
251 }
252 ];
253 condition = [ ];
254 action = [
255 {
256 action = "climate.set_temperature";
257 target.device_id = "bfe22d32a4532f8ae991d6daffb48267";
258 data = {
259 hvac_mode = "heat";
260 temperature = 18;
261 };
262 }
263 ];
264 mode = "single";
265 }
266 {
267 id = "1766200000001";
268 alias = "Raise heat in morning";
269 trigger = [
270 {
271 platform = "time";
272 at = "06:00:00";
273 }
274 ];
275 condition = [ ];
276 action = [
277 {
278 action = "climate.set_temperature";
279 target.device_id = "bfe22d32a4532f8ae991d6daffb48267";
280 data = {
281 hvac_mode = "heat";
282 temperature = 21;
283 };
284 }
285 ];
286 mode = "single";
287 }
288 {
289 id = "1766153071796";
290 alias = "Close Garage Door";
291 trigger = [
292 {
293 platform = "device";
294 device_id = "d8dedd8cd0ce1488d9830c455bb0a761";
295 domain = "cover";
296 entity_id = "cf36763543169888aa106b1acb02ad72";
297 type = "opened";
298 for = {
299 hours = 0;
300 minutes = 10;
301 seconds = 0;
302 };
303 }
304 ];
305 condition = [ ];
306 action = [
307 {
308 device_id = "d8dedd8cd0ce1488d9830c455bb0a761";
309 domain = "cover";
310 entity_id = "cf36763543169888aa106b1acb02ad72";
311 type = "close";
312 }
313 ];
314 mode = "single";
315 }
316 ];
317 };
318 };
319
320 # Enable the OpenSSH daemon.
321 # services.openssh.enable = true;
322
323 security.pam.loginLimits = [
324 {
325 domain = "*";
326 type = "soft";
327 item = "nofile";
328 value = "8192";
329 }
330 ];
331
332 # Open ports in the firewall.
333 networking.firewall.allowedTCPPorts = [
334 8096 # jellyfin
335 5055 # jellyseer
336 3000 # vite dev port
337 1883 # MQTT for Tasmota devices
338 2300 # trmnl
339 5000 # Frigate web UI
340 8971 # Frigate API
341 config.services.home-assistant.config.http.server_port
342 ];
343 networking.firewall.allowedUDPPorts = [
344 ];
345 # networking.firewall.enable = false;
346
347 # This value determines the NixOS release from which the default
348 # settings for stateful data, like file locations and database versions
349 # on your system were taken. It‘s perfectly fine and recommended to leave
350 # this value at the release version of the first install of this system.
351 # Before changing this value read the documentation for this option
352 # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
353 system.stateVersion = "25.05"; # Did you read the comment?
354
355}