me like nix
0

Configure Feed

Select the types of activity you want to include in your feed.

1{ pkgs, lib, config, ... }: 2 3let 4 cfg = config.pi; 5 6 # Workaround from https://github.com/NixOS/nixos-hardware/blob/master/raspberry-pi/4/apply-overlays-dtmerge.nix 7 deviceTree_overlay = _final: prev: { 8 deviceTree = { 9 applyOverlays = prev.callPackage ./overlays/apply-overlays-dtmerge.nix { }; 10 compileDTS = prev.deviceTree.compileDTS; 11 }; 12 }; 13 14 # Custom libcamera with Raspberry Pi IPA/pipeline support 15 libcamera-rpi = pkgs.libcamera.overrideAttrs (old: { 16 mesonFlags = (old.mesonFlags or [ ]) ++ [ 17 "-Dipas=rpi/vc4,rpi/pisp" 18 "-Dpipelines=rpi/vc4,rpi/pisp" 19 ]; 20 }); 21 22 # rpicam-apps using custom libcamera 23 rpicam-apps = pkgs.stdenv.mkDerivation rec { 24 pname = "rpicam-apps"; 25 version = "1.11.1"; 26 27 src = pkgs.fetchFromGitHub { 28 owner = "raspberrypi"; 29 repo = "rpicam-apps"; 30 rev = "v${version}"; 31 hash = "sha256-hVoKbvWFeramPkHuibJwUgFOPS9v588+K8828a1fNnA="; 32 }; 33 34 nativeBuildInputs = with pkgs; [ 35 meson 36 ninja 37 pkg-config 38 ]; 39 40 buildInputs = [ 41 libcamera-rpi 42 pkgs.libdrm 43 pkgs.libexif 44 pkgs.libjpeg 45 pkgs.libpng 46 pkgs.libtiff 47 pkgs.boost 48 pkgs.ffmpeg 49 ]; 50 51 mesonFlags = [ 52 "-Denable_libav=enabled" 53 "-Denable_drm=enabled" 54 "-Denable_egl=disabled" 55 "-Denable_qt=disabled" 56 "-Denable_opencv=disabled" 57 "-Denable_tflite=disabled" 58 "-Denable_hailo=disabled" 59 ]; 60 61 meta = with lib; { 62 description = "Raspberry Pi camera applications"; 63 homepage = "https://github.com/raspberrypi/rpicam-apps"; 64 license = licenses.bsd2; 65 platforms = [ "aarch64-linux" ]; 66 }; 67 }; 68in 69{ 70 imports = [ ./wifi.nix ]; 71 72 options.pi = { 73 streamName = lib.mkOption { 74 type = lib.types.str; 75 description = "Name of the camera stream"; 76 }; 77 78 resolution = { 79 width = lib.mkOption { 80 type = lib.types.int; 81 default = 1920; 82 description = "Camera resolution width"; 83 }; 84 height = lib.mkOption { 85 type = lib.types.int; 86 default = 1080; 87 description = "Camera resolution height"; 88 }; 89 }; 90 91 framerate = lib.mkOption { 92 type = lib.types.int; 93 default = 30; 94 description = "Camera framerate"; 95 }; 96 97 deviceTreeFilter = lib.mkOption { 98 type = lib.types.str; 99 description = "Device tree filter pattern"; 100 }; 101 102 deviceTreeCompatible = lib.mkOption { 103 type = lib.types.str; 104 description = "Device tree compatible string (e.g., brcm,bcm2711)"; 105 }; 106 107 gpuMem = lib.mkOption { 108 type = lib.types.int; 109 default = 256; 110 description = "GPU memory allocation in MB"; 111 }; 112 113 flipCamera = lib.mkOption { 114 type = lib.types.bool; 115 default = false; 116 description = "Flip camera image vertically and horizontally (180 degree rotation)"; 117 }; 118 119 }; 120 121 config = { 122 nix.settings.trusted-users = [ "sean" ]; 123 124 # Enable DHCP for ethernet 125 networking.useDHCP = true; 126 # Add device tree overlay for dtmerge support 127 nixpkgs.overlays = [ deviceTree_overlay ]; 128 129 # Disable ZFS which isn't supported on Pi 130 boot.supportedFilesystems = lib.mkForce [ "vfat" "ext4" ]; 131 132 # Pi kernel lacks device-mapper, so use legacy initrd (not systemd) 133 boot.initrd.systemd.enable = false; 134 135 # Enable SSH for headless setup 136 services.openssh = { 137 enable = true; 138 settings = { 139 PasswordAuthentication = false; 140 PermitRootLogin = "no"; 141 }; 142 }; 143 144 # User config 145 users.users.sean = { 146 isNormalUser = true; 147 extraGroups = [ "wheel" "video" ]; 148 openssh.authorizedKeys.keys = [ 149 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc=" 150 "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIOIgEteUEW06dnBHe2z8vNLwz2iMKe8bba6JgMmOUpcBAAAABHNzaDo= sean@framework16" 151 ]; 152 }; 153 154 # Allow sudo without password for wheel group 155 security.sudo.wheelNeedsPassword = false; 156 157 # go2rtc for camera streaming to Home Assistant 158 services.go2rtc = { 159 enable = true; 160 settings = { 161 ffmpeg.bin = "${pkgs.ffmpeg}/bin/ffmpeg"; 162 streams = { 163 "${cfg.streamName}" = "exec:${rpicam-apps}/bin/rpicam-vid -t 0 --width ${toString cfg.resolution.width} --height ${toString cfg.resolution.height} --framerate ${toString cfg.framerate} --codec h264 --inline${lib.optionalString cfg.flipCamera " --vflip --hflip"} -o -"; 164 }; 165 }; 166 }; 167 168 # udev rule to give video group access to DMA heap devices (required for libcamera) 169 services.udev.extraRules = '' 170 SUBSYSTEM=="dma_heap", GROUP="video", MODE="0660" 171 ''; 172 173 # Override go2rtc systemd service to run as root for camera access 174 systemd.services.go2rtc.serviceConfig = { 175 User = lib.mkForce "root"; 176 }; 177 178 # Camera and system tools 179 environment.systemPackages = [ 180 pkgs.ffmpeg 181 pkgs.libraspberrypi 182 libcamera-rpi 183 rpicam-apps 184 pkgs.v4l-utils 185 ]; 186 187 # Device tree configuration for Pi Camera v3 (IMX708) 188 hardware.deviceTree.filter = cfg.deviceTreeFilter; 189 hardware.deviceTree.overlays = [ 190 { 191 name = "imx708-overlay"; 192 dtsText = '' 193 // SPDX-License-Identifier: GPL-2.0-only 194 // Definitions for IMX708 camera module on VC I2C bus 195 /dts-v1/; 196 /plugin/; 197 198 /{ 199 compatible = "${cfg.deviceTreeCompatible}"; 200 201 fragment@0 { 202 target = <&i2c0if>; 203 __overlay__ { 204 status = "okay"; 205 }; 206 }; 207 208 clk_frag: fragment@1 { 209 target = <&cam1_clk>; 210 __overlay__ { 211 status = "okay"; 212 clock-frequency = <24000000>; 213 }; 214 }; 215 216 fragment@2 { 217 target = <&i2c0mux>; 218 __overlay__ { 219 status = "okay"; 220 }; 221 }; 222 223 reg_frag: fragment@3 { 224 target = <&cam1_reg>; 225 cam_reg: __overlay__ { 226 startup-delay-us = <70000>; 227 off-on-delay-us = <30000>; 228 regulator-min-microvolt = <2700000>; 229 regulator-max-microvolt = <2700000>; 230 }; 231 }; 232 233 i2c_frag: fragment@100 { 234 target = <&i2c_csi_dsi>; 235 __overlay__ { 236 #address-cells = <1>; 237 #size-cells = <0>; 238 status = "okay"; 239 240 // IMX708 sensor configuration (from imx708.dtsi) 241 cam_node: imx708@1a { 242 compatible = "sony,imx708"; 243 reg = <0x1a>; 244 status = "okay"; 245 246 clocks = <&cam1_clk>; 247 clock-names = "inclk"; 248 249 vana1-supply = <&cam1_reg>; 250 vana2-supply = <&cam_dummy_reg>; 251 vdig-supply = <&cam_dummy_reg>; 252 vddl-supply = <&cam_dummy_reg>; 253 254 rotation = <180>; 255 orientation = <2>; 256 257 port { 258 cam_endpoint: endpoint { 259 clock-lanes = <0>; 260 data-lanes = <1 2>; 261 clock-noncontinuous; 262 link-frequencies = 263 /bits/ 64 <450000000>; 264 }; 265 }; 266 }; 267 268 // VCM (autofocus motor) configuration 269 vcm_node: dw9817@c { 270 compatible = "dongwoon,dw9817-vcm"; 271 reg = <0x0c>; 272 status = "okay"; 273 VDD-supply = <&cam1_reg>; 274 }; 275 }; 276 }; 277 278 csi_frag: fragment@101 { 279 target = <&csi1>; 280 csi: __overlay__ { 281 status = "okay"; 282 brcm,media-controller; 283 284 port { 285 csi_ep: endpoint { 286 remote-endpoint = <&cam_endpoint>; 287 clock-lanes = <0>; 288 data-lanes = <1 2>; 289 clock-noncontinuous; 290 }; 291 }; 292 }; 293 }; 294 295 __overrides__ { 296 rotation = <&cam_node>,"rotation:0"; 297 orientation = <&cam_node>,"orientation:0"; 298 media-controller = <&csi>,"brcm,media-controller?"; 299 cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, 300 <&csi_frag>, "target:0=",<&csi0>, 301 <&clk_frag>, "target:0=",<&cam0_clk>, 302 <&reg_frag>, "target:0=",<&cam0_reg>, 303 <&cam_node>, "clocks:0=",<&cam0_clk>, 304 <&cam_node>, "vana1-supply:0=",<&cam0_reg>, 305 <&vcm_node>, "VDD-supply:0=",<&cam0_reg>; 306 vcm = <&vcm_node>, "status", 307 <0>, "=4"; 308 link-frequency = <&cam_endpoint>,"link-frequencies#0"; 309 }; 310 }; 311 312 &cam_endpoint { 313 remote-endpoint = <&csi_ep>; 314 }; 315 ''; 316 } 317 ]; 318 319 # Raspberry Pi firmware for camera 320 hardware.enableRedistributableFirmware = true; 321 322 # Add camera config and overlays to firmware partition 323 sdImage.populateFirmwareCommands = lib.mkAfter '' 324 chmod u+w ./firmware/config.txt 325 cat >> ./firmware/config.txt << EOF 326 327# Camera support - Pi Camera v3 (IMX708) 328gpu_mem=${toString cfg.gpuMem} 329EOF 330 331 # Copy device tree overlays for camera auto-detect 332 if [ -d ${pkgs.raspberrypifw}/share/raspberrypi/boot/overlays ]; then 333 cp -r ${pkgs.raspberrypifw}/share/raspberrypi/boot/overlays ./firmware/ 334 fi 335 ''; 336 337 # Firewall 338 networking.firewall.allowedTCPPorts = [ 339 22 # SSH 340 1984 # go2rtc API 341 8554 # RTSP 342 ]; 343 }; 344}