me like nix
0

Configure Feed

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

add pi config for libcamera

author
Sean Aye
date (Mar 22, 2026, 8:03 PM -0400) commit 41ca9e0d parent 7dfe3acc change-id qwztuyrz
+378 -10
+10
flake.nix
··· 93 93 "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix" 94 94 nixos-hardware.nixosModules.raspberry-pi-4 95 95 ./hosts/pi/configuration.nix 96 + 97 + # Allow missing kernel modules (Pi kernel doesn't have all x86 modules) 98 + # See: https://github.com/NixOS/nixpkgs/issues/154163 99 + ({ 100 + nixpkgs.overlays = [ 101 + (final: super: { 102 + makeModulesClosure = x: super.makeModulesClosure (x // { allowMissing = true; }); 103 + }) 104 + ]; 105 + }) 96 106 ]; 97 107 specialArgs = { inherit inputs; }; 98 108 };
+248 -10
hosts/pi/configuration.nix
··· 1 - { pkgs, lib, ... }: 1 + { pkgs, lib, config, ... }: 2 + 3 + let 4 + # Workaround from https://github.com/NixOS/nixos-hardware/blob/master/raspberry-pi/4/apply-overlays-dtmerge.nix 5 + deviceTree_overlay = _final: prev: { 6 + deviceTree = { 7 + applyOverlays = prev.callPackage ./overlays/apply-overlays-dtmerge.nix { }; 8 + compileDTS = prev.deviceTree.compileDTS; 9 + }; 10 + }; 11 + 12 + # Custom libcamera with Raspberry Pi IPA/pipeline support 13 + libcamera-rpi = pkgs.libcamera.overrideAttrs (old: { 14 + mesonFlags = (old.mesonFlags or [ ]) ++ [ 15 + "-Dipas=rpi/vc4,rpi/pisp" 16 + "-Dpipelines=rpi/vc4,rpi/pisp" 17 + ]; 18 + }); 19 + 20 + # rpicam-apps using custom libcamera 21 + rpicam-apps = pkgs.stdenv.mkDerivation rec { 22 + pname = "rpicam-apps"; 23 + version = "1.11.1"; 24 + 25 + src = pkgs.fetchFromGitHub { 26 + owner = "raspberrypi"; 27 + repo = "rpicam-apps"; 28 + rev = "v${version}"; 29 + hash = "sha256-hVoKbvWFeramPkHuibJwUgFOPS9v588+K8828a1fNnA="; 30 + }; 31 + 32 + nativeBuildInputs = with pkgs; [ 33 + meson 34 + ninja 35 + pkg-config 36 + ]; 2 37 38 + buildInputs = [ 39 + libcamera-rpi 40 + pkgs.libdrm 41 + pkgs.libexif 42 + pkgs.libjpeg 43 + pkgs.libpng 44 + pkgs.libtiff 45 + pkgs.boost 46 + pkgs.ffmpeg 47 + ]; 48 + 49 + mesonFlags = [ 50 + "-Denable_libav=enabled" 51 + "-Denable_drm=enabled" 52 + "-Denable_egl=disabled" 53 + "-Denable_qt=disabled" 54 + "-Denable_opencv=disabled" 55 + "-Denable_tflite=disabled" 56 + "-Denable_hailo=disabled" 57 + ]; 58 + 59 + meta = with lib; { 60 + description = "Raspberry Pi camera applications"; 61 + homepage = "https://github.com/raspberrypi/rpicam-apps"; 62 + license = licenses.bsd2; 63 + platforms = [ "aarch64-linux" ]; 64 + }; 65 + }; 66 + in 3 67 { 4 68 networking.hostName = "pi"; 69 + 70 + # Add device tree overlay for dtmerge support 71 + nixpkgs.overlays = [ deviceTree_overlay ]; 5 72 6 73 # Disable ZFS which isn't supported on Pi 7 74 boot.supportedFilesystems = lib.mkForce [ "vfat" "ext4" ]; 75 + 76 + # Pi kernel lacks device-mapper, so use legacy initrd (not systemd) 77 + boot.initrd.systemd.enable = false; 8 78 9 79 # Enable SSH for headless setup 10 80 services.openssh = { ··· 27 97 # Allow sudo without password for wheel group 28 98 security.sudo.wheelNeedsPassword = false; 29 99 30 - # Camera support 31 - hardware.raspberry-pi."4" = { 32 - fkms-3d.enable = true; 33 - }; 34 - 35 100 # go2rtc for camera streaming to Home Assistant 36 101 services.go2rtc = { 37 102 enable = true; 38 103 settings = { 104 + ffmpeg.bin = "${pkgs.ffmpeg}/bin/ffmpeg"; 39 105 streams = { 40 - picam = "exec:rpicam-vid -t 0 --inline --width 1920 --height 1080 --framerate 30 -o -"; 106 + # Use rpicam-vid for h264 streaming 107 + picam = "exec:${rpicam-apps}/bin/rpicam-vid -t 0 --width 1920 --height 1080 --framerate 30 --codec h264 --inline -o -"; 41 108 }; 42 109 }; 43 110 }; 44 111 112 + # udev rule to give video group access to DMA heap devices (required for libcamera) 113 + services.udev.extraRules = '' 114 + SUBSYSTEM=="dma_heap", GROUP="video", MODE="0660" 115 + ''; 116 + 117 + # Override go2rtc systemd service to run as root for camera access 118 + systemd.services.go2rtc.serviceConfig = { 119 + User = lib.mkForce "root"; 120 + }; 121 + 122 + # Camera and system tools 123 + environment.systemPackages = [ 124 + pkgs.ffmpeg 125 + pkgs.libraspberrypi # for vcgencmd 126 + libcamera-rpi # custom libcamera with Pi support 127 + rpicam-apps # rpicam-vid, rpicam-still, etc. 128 + pkgs.v4l-utils # for v4l2-ctl debugging 129 + ]; 130 + 131 + # Device tree configuration for Pi Camera v3 (IMX708) 132 + # Based on https://github.com/raspberrypi/linux/blob/rpi-6.6.y/arch/arm/boot/dts/overlays/imx708-overlay.dts 133 + # and https://github.com/wagdav/homelab/blob/master/modules/camera-rpi-v1/default.nix 134 + hardware.deviceTree.filter = "bcm2711-rpi-4*.dtb"; 135 + hardware.deviceTree.overlays = [ 136 + { 137 + name = "imx708-overlay"; 138 + dtsText = '' 139 + // SPDX-License-Identifier: GPL-2.0-only 140 + // Definitions for IMX708 camera module on VC I2C bus 141 + /dts-v1/; 142 + /plugin/; 143 + 144 + /{ 145 + compatible = "brcm,bcm2711"; 146 + 147 + fragment@0 { 148 + target = <&i2c0if>; 149 + __overlay__ { 150 + status = "okay"; 151 + }; 152 + }; 153 + 154 + clk_frag: fragment@1 { 155 + target = <&cam1_clk>; 156 + __overlay__ { 157 + status = "okay"; 158 + clock-frequency = <24000000>; 159 + }; 160 + }; 161 + 162 + fragment@2 { 163 + target = <&i2c0mux>; 164 + __overlay__ { 165 + status = "okay"; 166 + }; 167 + }; 168 + 169 + reg_frag: fragment@3 { 170 + target = <&cam1_reg>; 171 + cam_reg: __overlay__ { 172 + startup-delay-us = <70000>; 173 + off-on-delay-us = <30000>; 174 + regulator-min-microvolt = <2700000>; 175 + regulator-max-microvolt = <2700000>; 176 + }; 177 + }; 178 + 179 + i2c_frag: fragment@100 { 180 + target = <&i2c_csi_dsi>; 181 + __overlay__ { 182 + #address-cells = <1>; 183 + #size-cells = <0>; 184 + status = "okay"; 185 + 186 + // IMX708 sensor configuration (from imx708.dtsi) 187 + cam_node: imx708@1a { 188 + compatible = "sony,imx708"; 189 + reg = <0x1a>; 190 + status = "okay"; 191 + 192 + clocks = <&cam1_clk>; 193 + clock-names = "inclk"; 194 + 195 + vana1-supply = <&cam1_reg>; 196 + vana2-supply = <&cam_dummy_reg>; 197 + vdig-supply = <&cam_dummy_reg>; 198 + vddl-supply = <&cam_dummy_reg>; 199 + 200 + rotation = <180>; 201 + orientation = <2>; 202 + 203 + port { 204 + cam_endpoint: endpoint { 205 + clock-lanes = <0>; 206 + data-lanes = <1 2>; 207 + clock-noncontinuous; 208 + link-frequencies = 209 + /bits/ 64 <450000000>; 210 + }; 211 + }; 212 + }; 213 + 214 + // VCM (autofocus motor) configuration 215 + vcm_node: dw9817@c { 216 + compatible = "dongwoon,dw9817-vcm"; 217 + reg = <0x0c>; 218 + status = "okay"; 219 + VDD-supply = <&cam1_reg>; 220 + }; 221 + }; 222 + }; 223 + 224 + csi_frag: fragment@101 { 225 + target = <&csi1>; 226 + csi: __overlay__ { 227 + status = "okay"; 228 + brcm,media-controller; 229 + 230 + port { 231 + csi_ep: endpoint { 232 + remote-endpoint = <&cam_endpoint>; 233 + clock-lanes = <0>; 234 + data-lanes = <1 2>; 235 + clock-noncontinuous; 236 + }; 237 + }; 238 + }; 239 + }; 240 + 241 + __overrides__ { 242 + rotation = <&cam_node>,"rotation:0"; 243 + orientation = <&cam_node>,"orientation:0"; 244 + media-controller = <&csi>,"brcm,media-controller?"; 245 + cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, 246 + <&csi_frag>, "target:0=",<&csi0>, 247 + <&clk_frag>, "target:0=",<&cam0_clk>, 248 + <&reg_frag>, "target:0=",<&cam0_reg>, 249 + <&cam_node>, "clocks:0=",<&cam0_clk>, 250 + <&cam_node>, "vana1-supply:0=",<&cam0_reg>, 251 + <&vcm_node>, "VDD-supply:0=",<&cam0_reg>; 252 + vcm = <&vcm_node>, "status", 253 + <0>, "=4"; 254 + link-frequency = <&cam_endpoint>,"link-frequencies#0"; 255 + }; 256 + }; 257 + 258 + &cam_endpoint { 259 + remote-endpoint = <&csi_ep>; 260 + }; 261 + ''; 262 + } 263 + ]; 264 + 265 + # Raspberry Pi firmware for camera 266 + hardware.enableRedistributableFirmware = true; 267 + 268 + # Add camera config and overlays to firmware partition 269 + sdImage.populateFirmwareCommands = lib.mkAfter '' 270 + chmod u+w ./firmware/config.txt 271 + cat >> ./firmware/config.txt << EOF 272 + 273 + # Camera support - Pi Camera v3 (IMX708) 274 + gpu_mem=256 275 + EOF 276 + 277 + # Copy device tree overlays for camera auto-detect 278 + if [ -d ${pkgs.raspberrypifw}/share/raspberrypi/boot/overlays ]; then 279 + cp -r ${pkgs.raspberrypifw}/share/raspberrypi/boot/overlays ./firmware/ 280 + fi 281 + ''; 282 + 45 283 # Networking 46 284 networking.networkmanager.enable = true; 47 285 48 286 # Firewall 49 287 networking.firewall.allowedTCPPorts = [ 50 - 22 # SSH 51 - 1984 # go2rtc API 52 - 8554 # RTSP 288 + 22 # SSH 289 + 1984 # go2rtc API 290 + 8554 # RTSP 53 291 ]; 54 292 55 293 system.stateVersion = "24.11";
+50
hosts/pi/overlays/apply-overlays-dtmerge.nix
··· 1 + # modification of nixpkgs deviceTree.applyOverlays to resolve https://github.com/NixOS/nixpkgs/issues/125354 2 + # derived from https://github.com/NixOS/nixpkgs/blob/916ca8f2b0c208def051f8ea9760c534a40309db/pkgs/os-specific/linux/device-tree/default.nix 3 + { lib, stdenvNoCC, dtc, libraspberrypi }: 4 + 5 + with lib; (base: overlays': stdenvNoCC.mkDerivation { 6 + name = "device-tree-overlays"; 7 + nativeBuildInputs = [ dtc libraspberrypi ]; 8 + buildCommand = 9 + let 10 + overlays = toList overlays'; 11 + in 12 + '' 13 + mkdir -p $out 14 + cd "${base}" 15 + find . -type f -name '*.dtb' -print0 \ 16 + | xargs -0 cp -v --no-preserve=mode --target-directory "$out" --parents 17 + 18 + for dtb in $(find "$out" -type f -name '*.dtb'); do 19 + dtbCompat=$(fdtget -t s "$dtb" / compatible 2>/dev/null || true) 20 + # skip files without `compatible` string 21 + test -z "$dtbCompat" && continue 22 + 23 + ${flip (concatMapStringsSep "\n") overlays (o: '' 24 + overlayCompat="$(fdtget -t s "${o.dtboFile}" / compatible)" 25 + 26 + # skip incompatible and non-matching overlays 27 + if [[ ! "$dtbCompat" =~ "$overlayCompat" ]]; then 28 + echo "Skipping overlay ${o.name}: incompatible with $(basename "$dtb")" 29 + elif ${if ((o.filter or null) == null) then "false" else '' 30 + [[ "''${dtb//${o.filter}/}" == "$dtb" ]] 31 + ''} 32 + then 33 + echo "Skipping overlay ${o.name}: filter does not match $(basename "$dtb")" 34 + else 35 + echo -n "Applying overlay ${o.name} to $(basename "$dtb")... " 36 + mv "$dtb"{,.in} 37 + 38 + # dtmerge requires a .dtbo ext for dtbo files, otherwise it adds it to the given file implicitly 39 + dtboWithExt="$TMPDIR/$(basename "${o.dtboFile}").dtbo" 40 + cp -r ${o.dtboFile} "$dtboWithExt" 41 + 42 + dtmerge "$dtb.in" "$dtb" "$dtboWithExt" 43 + 44 + echo "ok" 45 + rm "$dtb.in" "$dtboWithExt" 46 + fi 47 + '')} 48 + 49 + done''; 50 + })
+9
packages/libcamera-rpi.nix
··· 1 + # Override libcamera to include Raspberry Pi IPA and pipeline support 2 + { pkgs }: 3 + 4 + pkgs.libcamera.overrideAttrs (old: { 5 + mesonFlags = old.mesonFlags ++ [ 6 + "-Dipas=rpi/vc4,rpi/pisp" 7 + "-Dpipelines=rpi/vc4,rpi/pisp" 8 + ]; 9 + })
+61
packages/rpicam-apps.nix
··· 1 + { 2 + lib, 3 + stdenv, 4 + fetchFromGitHub, 5 + meson, 6 + ninja, 7 + pkg-config, 8 + libcamera-rpi, # Custom libcamera with Pi support 9 + libdrm, 10 + libexif, 11 + libjpeg, 12 + libpng, 13 + libtiff, 14 + boost, 15 + ffmpeg, 16 + }: 17 + 18 + stdenv.mkDerivation rec { 19 + pname = "rpicam-apps"; 20 + version = "1.5.3"; 21 + 22 + src = fetchFromGitHub { 23 + owner = "raspberrypi"; 24 + repo = "rpicam-apps"; 25 + rev = "v${version}"; 26 + hash = "sha256-0000000000000000000000000000000000000000000="; # Placeholder - will be updated on first build 27 + }; 28 + 29 + nativeBuildInputs = [ 30 + meson 31 + ninja 32 + pkg-config 33 + ]; 34 + 35 + buildInputs = [ 36 + libcamera-rpi 37 + libdrm 38 + libexif 39 + libjpeg 40 + libpng 41 + libtiff 42 + boost 43 + ffmpeg 44 + ]; 45 + 46 + mesonFlags = [ 47 + "-Denable_libav=enabled" 48 + "-Denable_drm=enabled" 49 + "-Denable_egl=disabled" 50 + "-Denable_qt=disabled" 51 + "-Denable_opencv=disabled" 52 + "-Denable_tflite=disabled" 53 + ]; 54 + 55 + meta = with lib; { 56 + description = "Raspberry Pi camera applications"; 57 + homepage = "https://github.com/raspberrypi/rpicam-apps"; 58 + license = licenses.bsd2; 59 + platforms = [ "aarch64-linux" ]; 60 + }; 61 + }