# Python packages forza_trigger.py imports that aren't in nixpkgs. Returns # an attrset consumed by ./default.nix. # # Bumping a version: change `version` and `hash`, then `nix build` — Nix # fails with the new sha256 in the error message, paste it back in. { lib, pkgs, python ? pkgs.python3, }: let py = python.pkgs; in rec { # DualSense controller library (yesbotics/dualsense-controller-python). # Bundles its own hidapi-cffi binding; replaces the previous pydualsense + # hidapi-usb pair. The library's transport model writes the HID output # report on every input report tick BUT only when an output state actually # changed since the last write — so we get on-demand HID writes for free # without disabling any background thread (the thing pydualsense made us # work around at ~250 Hz). BT CRC32 is computed correctly inside the # library's Bt31OutReport.to_bytes. dualsense-controller = py.buildPythonPackage rec { pname = "dualsense-controller"; version = "0.3.1"; pyproject = true; # PyPI normalizes the sdist filename to underscore form (PEP 625) but # the project URL slug is dasherized. fetchPypi assumes they match; # passing the underscored pname matches the on-disk filename. src = py.fetchPypi { pname = "dualsense_controller"; inherit version; hash = "sha256-yy1MQeRPqaLvoXaAigQd3gPFsFLbwKqrD4mP2zQqcFw="; }; nativeBuildInputs = [ py.poetry-core ]; # Upstream's pyproject pins pyee ^11 and cffi ^1.15. nixpkgs ships # pyee 13 and cffi 2. The library only uses stable APIs — pyee # `EventEmitter`/`on`/`emit` and cffi `FFI`/`cdef`/`dlopen`/`new`/ # `buffer` — that work unchanged on the newer versions. Relax both. pythonRelaxDeps = [ "pyee" "cffi" ]; propagatedBuildInputs = with py; [ pyee cffi deprecated ]; # Same hidapi-binding pattern as our previous hidapi-usb derivation. # The library walks a tuple of soname strings via ffi.dlopen() until # one resolves; pin the two Linux hidraw entries to absolute store # paths so the wrapped Python in writePython3Bin doesn't need # LD_LIBRARY_PATH wrapping. The libusb / iohidmanager / dylib / dll # entries are dead code on Linux. --replace-fail makes a rename in # upstream's tuple a loud build error rather than a silent ImportError # at runtime. postPatch = '' substituteInPlace src/dualsense_controller/core/hidapi/hidapi.py \ --replace-fail "'libhidapi-hidraw.so'," "'${pkgs.hidapi}/lib/libhidapi-hidraw.so'," \ --replace-fail "'libhidapi-hidraw.so.0'," "'${pkgs.hidapi}/lib/libhidapi-hidraw.so.0'," ''; pythonImportsCheck = [ "dualsense_controller" ]; meta = { description = "Use DualSense Controller with Python"; homepage = "https://github.com/yesbotics/dualsense-controller-python"; license = lib.licenses.mit; }; }; # Single-file Forza UDP packet parser (nettrom/forza_motorsport). Pinned to # a known-good commit; the repo is dormant (last commit 2021) but the FH4 # packet layout is frozen and FH5 reuses it byte-for-byte. fdp = py.buildPythonPackage { pname = "fdp"; version = "0-unstable-2021-05-28"; format = "other"; src = pkgs.fetchurl { url = "https://raw.githubusercontent.com/nettrom/forza_motorsport/61845cb7ff4082211292a51ce3c49edbfd2d6503/fdp.py"; hash = "sha256-osFaVF9VaEzU4dp3x6KN6OF7SXsd9ZBwvilU+xTT7mM="; }; dontUnpack = true; installPhase = '' runHook preInstall install -Dm644 $src $out/${python.sitePackages}/fdp.py runHook postInstall ''; pythonImportsCheck = [ "fdp" ]; meta = { description = "ForzaDataPacket — Forza Motorsport / Horizon UDP packet parser"; homepage = "https://github.com/nettrom/forza_motorsport"; license = lib.licenses.mit; }; }; }