Cross build raspberry pi 0 2w, using camera v2

I only asking for help to have nix flake crossbuild code to use picamera2.

I am a hardware guy trying to do this whole project called Cat Traption.

Cat Traption Project:

i have a working raspberry pi 2 controlling a animal trap.

I have PIR sensor for motion.

I have the python code working.

My next box, I want to add pi camera V2 to detect and ID a CAT.

on a second raspberry pi “Rpi02w” i have installed nixOS.

Flow setup : On my Desktop I installed NixOS 25.11 . I have successfully created an image for SD card for Rpi02w (crossbuild). Rpi02w boots headless. No camera yet.

Rpi02w packages. . (Nix).

packages = with pkgs; [ (let pythonEnv = python3.withPackages (ps: [ ps.opencv-python-headless ps.rpi-gpio ]); in pythonEnv) ]; };

Here is the results from ‘free -h’ on the Rpi02w.

free -h

           total        used        free      shared  buff/cache   available

Mem: 453Mi 112Mi 89Mi 4.1Mi 266Mi 341Mi

Swap: 226Mi 0B 226Mi

Version 1: My intent is to make this project an open source and train TnR groups (trap Neuter Return) how to use this. Field application Rpi02w, no wifi , just purely local embedded. This is for TnR cat groups so they don’t trap skunks, or any other animal. Just cats.

I will pre-process CAT ID models with the desktop machine.

Version 2.0 of cat trap, I will have a list “not this cat”. I don’t want to trap cats that has already nuetered. I can have python code take pictures of trapped cat for post-processing to make a list of already trapped cats. Somekind of face identification.

Then have raspberry pi check the file on usb stick to see if already trapped.

Cost is pretty much a concern. So I bought three pi camera v2.

My 1st version uses raspberry pi 2 (very old) and only has PIR motion sensor working. It has been used in the feild.

I know there is a huge big step between my working hardware and getting people to duplicate it. But I am stuck trying to get pi camera v2 to cross build using nix flake.

software flow -

PIR sensor to trigger camera as cat enters trap. no videos.

Decide Yes it is a cat. (not version 2.0) yet.

trigger motor, trap cat.

take up to 20 more pics of trapped cat.

Shutdown Raspberry PI (save power).

I need to add picamera2 to the Rpi02w packages.

nixpkgs don’t have picamera2, or dependecies don’t get built correctly.

Oh yea, Only in the last 8 months have I worked with NixOS. So everything is still being learned.

attached are 2 files “zero2w.nix” and “flake.nix”.

Here is the latest error I am getting. . . I guess simplejpeg uses cython but cython is not available in python3.12 ???

Yes I am getting lost in so many hiearchies of this project.

python3.12-simplejpeg> cython~=3.0.0

python3.12> reading sources… [ 28%] library/asyncio-exceptions

error: Cannot build ‘/nix/store/mdfznzslfz9hxnzm0rph9idvbaql5w85-python3.12-simplejpeg-1.8.2.drv’.

   Reason: builder failed with exit code 1.

   Output paths:

     /nix/store/38c0j0hqak6hzdp9aflaflwkgbh68zir-python3.12-simplejpeg-1.8.2-dist

     /nix/store/gh6gw7cp8yaq28kvi3m1bp1wlvdv3ha3-python3.12-simplejpeg-1.8.2

   Last 25 log lines:
{
  description = "Flake for building a Raspberry Pi Zero 2 SD image";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
    deploy-rs.url = "github:serokell/deploy-rs";
  };

  outputs = { self, nixpkgs, deploy-rs, ... }: rec {
    nixosConfigurations = {
      zero2w = nixpkgs.lib.nixosSystem {
        modules = [
          "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix"
          ./zero2w.nix
        ];
      };
    };

    deploy = {
      user = "root";
      nodes = {
        zero2w = {
          hostname = "zero2w";
          profiles.system.path =
            deploy-rs.lib.aarch64-linux.activate.nixos self.nixosConfigurations.zero2w;
        };
      };
    };
  };
}

{ lib
, modulesPath
, pkgs
, ...
}:

{
  imports = [
    ./sd-image.nix
  ];

  ########################################
  # Nix / System
  ########################################
  nixpkgs = {
    overlays = [
      (final: super: {
        makeModulesClosure = x: super.makeModulesClosure (x // { allowMissing = true; });
      })
    ];
    hostPlatform = "aarch64-linux";
  };

  nix.settings.trusted-users = [ "@wheel" ];
  system.stateVersion = "25.11";

  ########################################
  # Enable Nix flakes (for build machine)
  ########################################
  nix = {
    package = pkgs.nixVersions.stable;   # nixFlakes replaced
    extraOptions = ''
      experimental-features = nix-command flakes
    '';
  };

  ########################################
  # Boot
  ########################################
  boot = {
    kernelPackages = pkgs.linuxPackages_rpi02w;

    kernelModules = [
      "bcm2835-v4l2"
      "i2c-bcm2835"
      "i2c-dev"
    ];

    initrd.availableKernelModules = [
      "xhci_pci"
      "usbhid"
      "usb_storage"
    ];

    loader = {
      grub.enable = false;
      generic-extlinux-compatible.enable = true;
    };

    swraid.enable = lib.mkForce false;
  };

  ########################################
  # Hardware
  ########################################
  hardware = {
    
    enableRedistributableFirmware = true;
    firmware = [ pkgs.raspberrypiWirelessFirmware ];
    i2c.enable = true;

    deviceTree = {
      enable = true;
      kernelPackage = pkgs.linuxPackages_rpi02w.kernel;  # Use same as boot.kernelPackages
      filter =  "*2837*" ; # Broadcom chip on Pi Zero 2 W
      overlays = [
        {
          name     = "imx219";
          dtboFile = "${pkgs.raspberrypifw}/share/raspberrypi/boot/overlays/imx219.dtbo";
        }
      ];
    };
  };

  ########################################
  # SD Image
  ########################################
  sdImage = {
    compressImage = false;
    imageName = "zero2.img";

    extraFirmwareConfig = {
       start_x = 1; 
       gpu_mem = 64; 
       hdmi_group = 2; 
       hdmi_mode = 82; 
       dtoverlay = "imx219";
    };
  };

  ########################################
  # Swap
  ########################################
  zramSwap = {
    enable = true;
    algorithm = "zstd";
  };



  ########################################
  # Services
  ########################################
  services = {
    sshd.enable = true;
    timesyncd.enable = true;
    getty.autologinUser = "bob";
  };

  ########################################
  # Security
  ########################################
  security.sudo = {
    enable = true;
    wheelNeedsPassword = false;
  };



  ########################################
  # System Packages
  ########################################

  environment.systemPackages = with pkgs; [
  libcamera
  ];




  ########################################
  # Users
  ########################################
  users.users.bob = {
    isNormalUser = true;
    home = "/home/bob";
    description = "Bob";
    extraGroups = [ "wheel" "video" ];
    password = "junk-redacted";
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 crap numbers"
    ];
  };
  ########################################
  # Bob's Python Environment (modern PEP 517)
  ########################################
  users.users.bob.packages = let
    python3 = pkgs.python312; 
    python3Packages = pkgs.python312Packages;

    libcamera = pkgs.libcamera;
    libjpeg_turbo = pkgs.libjpeg_turbo;

    picamera2 = python3Packages.buildPythonPackage rec {
      pname = "picamera2";
      version = "0.3.30";

      src = pkgs.fetchFromGitHub {
        inherit pname version;
        owner = "raspberrypi";
        repo = pname;
        rev = "v${version}";
        sha256 = "sha256-DRhTBqEaDIriOvRgOQxuu0+0FdCpTTJ3DaTNLRIwgDE=";
      };

      pyproject = true;
      build-system = [ python3Packages.setuptools ];

      propagatedBuildInputs = with python3Packages; [
        numpy
        opencv-python
        libcamera
        pillow
        pyqt5
        kmsxx

        (buildPythonPackage rec {
          pname = "pidng";
          version = "4.0.9";
          pyproject = true;
          src = pkgs.fetchPypi {
            inherit pname version;
            sha256 = "sha256-Vg6wCAhvinFf2eGrmYgXp9TIUAp/Fhuc5q9asnUB+Cw=";
          };
          buildInputs = [ numpy ];
          build-system = [ setuptools ];
          doCheck = false;
        })

        (buildPythonPackage rec {
          pname = "simplejpeg";
          version = "1.8.2";
          pyproject = true;
          dontUseCmakeConfigure = true;
          src = pkgs.fetchFromGitHub {
            owner = "jfolz";
            repo = pname;
            rev = "c6051d5984987bc2a7f476778cde339a87711412";
            sha256 = "sha256-SsDSJUUJQ5MjbOBNwVye4mn8yHBWvV9h0EYzTo4hGRc=";
          };
          build-system = [ setuptools ];
          propagatedBuildInputs = [ numpy libjpeg_turbo ];
          nativeBuildInputs = [ cython setuptools wheel pkgs.cmake ];
          patches = [
            (pkgs.fetchpatch {
              url = "https://github.com/jfolz/simplejpeg/compare/master...adminy:simplejpeg:patch-2.patch";
              sha256 = "sha256-DyhNZJ0QBxjJoT2PxGjnMzv4Kqf8sQ/71h3MsPI8F4o=";
            })
          ];
          doCheck = false;
        })

        (buildPythonPackage rec {
          pname = "videodev2";
          version = "0.0.4";
          pyproject = true;
          src = pkgs.fetchPypi {
            inherit pname version;
            sha256 = "sha256-w0unBJHRSMI6CMus2O+r60E8/1uqlDp1SKxKvR6xnio=";
          };
          build-system = [ setuptools ];
          nativeBuildInputs = [ setuptools wheel ];
          doCheck = false;
        })

        piexif
        (python-prctl.overrideAttrs (_: {
          doCheck = false;
          doInstallCheck = false;
        }))
        av
        libarchive-c
        tqdm
        jsonschema
      ];

      doCheck = false;
    };

    pythonEnv = pkgs.python312.withPackages (ps: [ picamera2 ]
    );

  in
    [ pythonEnv ];
}

I got past this issue by using a usb camera. $19 camera from microcenter.