me like nix
1{ ... }: {
2 flake.modules.nixos.pi-camera =
3 { pkgs, lib, config, ... }:
4 let
5 cfg = config.pi;
6 in
7 {
8 options.pi = {
9 streamName = lib.mkOption {
10 type = lib.types.str;
11 description = "Name of the camera stream";
12 };
13 resolution = {
14 width = lib.mkOption {
15 type = lib.types.int;
16 default = 1920;
17 description = "Camera resolution width";
18 };
19 height = lib.mkOption {
20 type = lib.types.int;
21 default = 1080;
22 description = "Camera resolution height";
23 };
24 };
25 framerate = lib.mkOption {
26 type = lib.types.int;
27 default = 30;
28 description = "Camera framerate";
29 };
30 gpuMem = lib.mkOption {
31 type = lib.types.int;
32 default = 256;
33 description = "GPU memory allocation in MB";
34 };
35 flipCamera = lib.mkOption {
36 type = lib.types.bool;
37 default = false;
38 description = "Flip camera image 180 degrees";
39 };
40 };
41
42 config = {
43 nix.settings.trusted-users = [ "sean" ];
44
45 networking.useDHCP = true;
46
47 services.openssh = {
48 enable = true;
49 settings = {
50 PasswordAuthentication = false;
51 PermitRootLogin = "no";
52 };
53 };
54
55 users.users.sean = {
56 isNormalUser = true;
57 extraGroups = [
58 "wheel"
59 "video"
60 ];
61 openssh.authorizedKeys.keys = [
62 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc="
63 "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIOIgEteUEW06dnBHe2z8vNLwz2iMKe8bba6JgMmOUpcBAAAABHNzaDo= sean@framework16"
64 ];
65 };
66
67 security.sudo.wheelNeedsPassword = false;
68
69 # Firmware config.txt: CMA and GPU memory
70 hardware.raspberry-pi.config.all = {
71 options.gpu_mem = {
72 enable = true;
73 value = cfg.gpuMem;
74 };
75 dt-overlays.vc4-kms-v3d.params.cma-256.enable = true;
76 };
77
78 services.go2rtc = {
79 enable = true;
80 settings = {
81 ffmpeg.bin = "${pkgs.ffmpeg}/bin/ffmpeg";
82 streams = {
83 "${cfg.streamName}" = "exec:${pkgs.rpi.rpicam-apps}/bin/rpicam-vid -t 0 --width ${toString cfg.resolution.width} --height ${toString cfg.resolution.height} --framerate ${toString cfg.framerate} --codec h264 --inline --autofocus-mode auto${lib.optionalString cfg.flipCamera " --vflip --hflip"} -o -";
84 };
85 };
86 };
87
88 services.udev.extraRules = ''
89 SUBSYSTEM=="dma_heap", GROUP="video", MODE="0660"
90 '';
91
92 systemd.services.go2rtc.serviceConfig = {
93 User = lib.mkForce "root";
94 SupplementaryGroups = [ "video" ];
95 };
96 systemd.services.go2rtc.environment = {
97 LIBCAMERA_IPA_MODULE_PATH = "${pkgs.rpi.libcamera}/lib/libcamera/ipa";
98 };
99
100 environment.systemPackages = [
101 pkgs.ffmpeg
102 pkgs.rpi.libcamera
103 pkgs.rpi.rpicam-apps
104 pkgs.v4l-utils
105 ];
106
107 networking.firewall.allowedTCPPorts = [
108 22
109 1984
110 8554
111 ];
112 };
113 };
114}