Files
nixos/hosts/yarn/forza-trigger/python-packages.nix
Simon Gardling 3865ceac0f
All checks were successful
Build and Deploy / mreow (push) Successful in 7m57s
Build and Deploy / yarn (push) Successful in 1m11s
Build and Deploy / muffin (push) Successful in 1m3s
fh5 things
2026-05-07 17:33:35 -04:00

117 lines
4.4 KiB
Nix

# 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=";
};
# Library bug fix: trigger-effect params 8-10 are never propagated to
# the OUT report. effect.vibration() puts the frequency in param9, so
# without this patch every vibration call ships frequency=0 to the
# controller and the trigger sits silently in vibration mode. The
# patch fixes update_out_report to read params 8/9/10 directly off
# the parent TriggerEffect state. Confirmed live with strace before
# patching: byte 31 (= L2 param9) was 0 every tick during slip events.
patches = [
../../../patches/dualsense-controller/0001-propagate-trigger-effect-params-8-10.patch
];
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;
};
};
}