Skip to content

JoeyEamigh/nixos-superbird

Repository files navigation

NixOS for the Spotify Car Thing

nixos-superbird is a project to help build custom Linux images for the Spotify Car Thing and easily install them. This is the first project (to my knowledge) to democratize Linux for the Superbird, and by far the easiest way to attain full control of the Car Thing.

This project was originally built in 24 hours for Car Thang during a hackathon.

If you would like to support the development of nixos-superbird and Car Thang, please consider sending us any old Car Things you may have lying around. They are rather expensive now.

Features

  • fully customizable NixOS
  • one-click guided installer
  • compressed BTRFS filesystem for maximum storage
  • support for Bluetooth and Bluetooth PAN (tetherless Car Thing, anyone?)
  • networked initrd for debugging
  • support for live deployments without rebuilding (thanks nix!)

Quick Setup

Head on over to https://github.com/JoeyEamigh/nixos-superbird-template and clone the template to quickly get started with nixos-superbird!

Setup

To use nixos-superbird, you must have either Nix installed on your computer, or have a Docker container with Nix (working on adding one). If you are not on an aarch64-linux machine (most of you), then you also need to have QEMU binfmt set up. Look up how to set that up on your distro.

  • check if it's installed by running ls /proc/sys/fs/binfmt_misc/
  • on Arch, you can just run pacman -S qemu-user-static-binfmt

Once that is set up, add this line to your /etc/nix/nix.conf and restart the Nix daemon:

extra-platforms = aarch64-linux

The most basic form of using nixos-superbird is a single flake.nix file.

{
  description = "NixOS Superbird configuration";
  inputs = {
    nixos-superbird.url = "github:joeyeamigh/nixos-superbird/main";
    nixpkgs.follows = "nixos-superbird/nixpkgs"; # if you need newer versions of apps you can override or PR this repo
  };

  outputs =
    {
      self,
      nixpkgs,
      nixos-superbird,
    }:
    let
      inherit (nixpkgs.lib) nixosSystem;
    in
    {
      nixosConfigurations = {
        superbird = nixosSystem {
          modules = [
            nixos-superbird.nixosModules.superbird
            (
              { ... }:
              {
                superbird.gui.kiosk = "https://github.com/JoeyEamigh/nixos-superbird";
                system.stateVersion = "24.11";
              }
            )
          ];
        };
      };
    };
}

I would recommend basing your config off of the ./examples/flake/ directory. It contains a basic flake along with deploy-rs for easy updates without reflashing your Superbird, and a Justfile with helpful scripts.

To build, run:

nix build '.#nixosConfigurations.superbird.config.system.build.installer'

Once you have Nix installed on your Superbird, you can make changes to your flake and run the push script in the Justfile to update the device without reflashing.

Configuration

To make this flake as easy to use as possible, not many things are directly configurable at the moment. You can obviously override anything I have set with lib.mkForce. You can view all superbird configuration options in ./modules/default.nix, and the defaults are listed below. If you would like to add more config options, feel free to PR with the config and an example.

{
  superbird = {
    bluetooth = {
      enable = true; # whether bluetooth is enabled
      name = "Superbird"; # name of the device as it broadcasts over bluetooth
    };

    gui = {
      enable = true; # whether cage (kiosk-mode wayland compositor) is enabled
      app = null; # full path to an app to run - i.e. "${pkgs.cog}/bin/cog"
      kiosk = null; # url to send a chromium kiosk (with basic gpu acceleration) to - i.e. "https://github.com/JoeyEamigh/nixos-superbird"
    };
    # you cannot have both app and kiosk set at the same time - if you need more control use app or disable gui and diy

    swap = {
      enable = true; # whether to create a swapfile
      size = 512; # size of said swapfile in MiB
    };

    qemu = false; # whether you are building an image to run IN qemu
  };
}

Installation

Once you have built an installer, it will be output to ./result. Due to the way that mkfs.btrfs works, the generated result/linux/rootfs.img will most likely be ~3x larger than it needs to be. To compress the image for flashing, first you must copy the files to another directory (since nix symlinks), then run the scripts/shrink-img.sh script. A convenience script installer is also included in the example flake Justfile which does this automatically.

mkdir ./out
cp -r ./result/* ./out/

cd ./out
sudo ./scripts/shrink-img.sh

Once you have shrunk the image, you are ready to install! Enter your new out directory, and run ./install.sh. This script will walk you through the install process.

For a fully scripted installer build, simply run just run-installer.

Post-Install

After the system is installed and booted, you will have to set up a wired network connection (which the installer took care of the first time around). The script at out/scripts/ssh.sh will configure your network based on the network interface detected during the install. This may change if you switch the USB port superbird is plugged into, so you can always change the interface name in out/ssh/interface.txt.

Known Issues

  • touchscreen calibration is sometimes incorrect
  • there's a mouse cursor on the screen

Troubleshooting

On some desktop environments, Network Manager will try to set up the new USB network interface and randomly disconnect in the middle of operations. If this happens, run nmcli device set <interface_name> managed no.

Notes

To make the install easier, I committed the SSH keys that the devices will use. This is not a problem as the only way to connect to this device is via USB. You can configure custom keys in your flake.nix if you so choose.

I am new to Nix and hate Python with a passion, so code quality could probably use some work. PRs welcome!

Prior Art

I would like to give a massive shoutout to alexcaoys. Their work on the linux-superbird-6.6.y kernel made this entire project possible.

I also must acknowledge the work bishopdynamics did on superbird-tool and of course frederic for introducing Car Thing hacking to the world.