me like nix
1{ ... }:
2{
3 flake.modules.nixos.home-automation =
4 { pkgs, ... }:
5 {
6 # MQTT broker for Home Assistant (Tasmota devices, Frigate)
7 services.mosquitto = {
8 enable = true;
9 listeners = [
10 {
11 acl = [ "pattern readwrite #" ];
12 omitPasswordAuth = true;
13 settings.allow_anonymous = true;
14 }
15 ];
16 };
17
18 # Frigate NVR for camera recording and AI object detection
19 services.frigate = {
20 enable = true;
21 hostname = "frigate";
22 settings = {
23 mqtt = {
24 enabled = true;
25 host = "localhost";
26 port = 1883;
27 };
28
29 detectors = {
30 cpu = {
31 type = "cpu";
32 num_threads = 2;
33 };
34 };
35
36 cameras = {
37 picam = {
38 enabled = true;
39 ffmpeg = {
40 hwaccel_args = "preset-nvidia-h264";
41 inputs = [
42 {
43 path = "rtsp://pi:8554/picam";
44 roles = [
45 "detect"
46 "record"
47 ];
48 }
49 ];
50 };
51 detect = {
52 enabled = true;
53 width = 1920;
54 height = 1080;
55 fps = 3;
56 };
57 record = {
58 enabled = true;
59 retain = {
60 days = 7;
61 mode = "active_objects";
62 };
63 };
64 snapshots = {
65 enabled = true;
66 bounding_box = true;
67 retain = {
68 default = 14;
69 };
70 };
71 objects = {
72 track = [
73 "person"
74 "dog"
75 "cat"
76 "car"
77 ];
78 };
79 zones = {
80 driveway = {
81 coordinates = "0,0.243,1,0.544,1,1,0,1,0,0.75";
82 objects = [
83 "person"
84 "car"
85 "dog"
86 "cat"
87 ];
88 };
89 };
90 };
91
92 pizerocam = {
93 enabled = true;
94 ffmpeg = {
95 hwaccel_args = "preset-nvidia-h264";
96 inputs = [
97 {
98 path = "rtsp://pizero:8554/pizerocam";
99 roles = [ "record" ];
100 }
101 ];
102 };
103 detect = {
104 enabled = false;
105 };
106 record = {
107 enabled = true;
108 retain = {
109 days = 2;
110 mode = "all";
111 };
112 };
113 };
114 };
115
116 record = {
117 enabled = true;
118 retain = {
119 days = 7;
120 mode = "active_objects";
121 };
122 };
123 };
124 };
125
126 # Frigate manages many ffmpeg child processes that ignore SIGTERM
127 systemd.services.frigate.serviceConfig = {
128 TimeoutStopSec = 5;
129 KillMode = "mixed";
130 };
131
132 # Home Assistant service
133 services.home-assistant = {
134 enable = true;
135 customComponents = with pkgs.home-assistant-custom-components; [
136 frigate
137 ];
138 extraComponents = [
139 "esphome"
140 "met"
141 "radio_browser"
142 "homekit"
143 "homekit_controller"
144 "isal"
145 "mqtt"
146 "tasmota"
147 "wiz"
148 "google_translate"
149 "ecobee"
150 "ibeacon"
151 "go2rtc"
152 "generic"
153 ];
154 config = {
155 homeassistant = {
156 time_zone = "America/Toronto";
157 };
158 default_config = { };
159 zeroconf = { };
160 mqtt = { };
161 automation = [
162 {
163 id = "1761448856909";
164 alias = "Lower heat at night";
165 trigger = [
166 {
167 platform = "time";
168 at = "23:00:00";
169 }
170 ];
171 condition = [ ];
172 action = [
173 {
174 action = "climate.set_temperature";
175 target.device_id = "bfe22d32a4532f8ae991d6daffb48267";
176 data = {
177 hvac_mode = "heat";
178 temperature = 18;
179 };
180 }
181 ];
182 mode = "single";
183 }
184 {
185 id = "1766200000001";
186 alias = "Raise heat in morning";
187 trigger = [
188 {
189 platform = "time";
190 at = "07:00:00";
191 }
192 ];
193 condition = [ ];
194 action = [
195 {
196 action = "climate.set_temperature";
197 target.device_id = "bfe22d32a4532f8ae991d6daffb48267";
198 data = {
199 hvac_mode = "heat";
200 temperature = 20;
201 };
202 }
203 ];
204 mode = "single";
205 }
206 {
207 id = "1766153071796";
208 alias = "Close Garage Door";
209 trigger = [
210 {
211 platform = "device";
212 device_id = "d8dedd8cd0ce1488d9830c455bb0a761";
213 domain = "cover";
214 entity_id = "cf36763543169888aa106b1acb02ad72";
215 type = "opened";
216 for = {
217 hours = 0;
218 minutes = 10;
219 seconds = 0;
220 };
221 }
222 ];
223 condition = [ ];
224 action = [
225 {
226 device_id = "d8dedd8cd0ce1488d9830c455bb0a761";
227 domain = "cover";
228 entity_id = "cf36763543169888aa106b1acb02ad72";
229 type = "close";
230 }
231 ];
232 mode = "single";
233 }
234 ];
235 };
236 };
237 };
238}