mrmime

mjm.home-assistant.enable = true;

mrmime runs Home Assistant to control automation in my house. The main things I use this for are controlling lights and monitoring temperature and humidity throughout the house.

microvm.mem = 1536;

mrmime has increased RAM, particularly because it needs more when it performs a backup.

services.udev.extraRules = ''
  SUBSYSTEM=="usb", ATTR{idVendor}=="10c4", ATTR{idProduct}=="ea60", GROUP="kvm", SYMLINK+="zigbee", TAG+="systemd"
'';

I prefer to use devices that work via Zigbee, so the host has a USB Zigbee adapter to connect to all of the devices. This device needs to be usable from the microvm user. It's also important to be able to consistently find the device, so udev is configured to symlink it to /dev/zigbee. Otherwise, the device node would have a path that depended on its location within the USB bus, which could change if it was plugged into a different port for instance. And finally, adding a "systemd" tag means that systemd will create a .device unit for it, which will be useful next.

systemd.services.zigbee-usb-vfio =
  let
    <<usbvfiod>>
  in
  {
    description = "USB VFIO for Zigbee Adapter";
    requiredBy = [ "microvm@mrmime.service" ];
    before = [ "microvm@mrmime.service" ];
    partOf = [ "microvm@mrmime.service" ];
    requires = [ "dev-zigbee.device" ];
    after = [ "dev-zigbee.device" ];
    serviceConfig = {
      Type = "exec";
      ExecStartPre = "-${pkgs.busybox}/bin/rm zigbee.sock";
      ExecStart = "${usbvfiod}/bin/usbvfiod --device /dev/zigbee --socket-path zigbee.sock";
      WorkingDirectory = "/var/lib/microvms/mrmime";
      User = "microvm";
      Group = "kvm";
      DeviceAllow = [ "/dev/zigbee" ];
    };
  };

All of my microVMs use cloud-hypervisor, which doesn't have built-in support for passthrough of USB devices. It does support VFIO user devices though, which means I can use usbvfiod to pass the device through. This service depends on the device being available, and starts as part of starting the VM itself. It exposes a socket at /var/lib/microvms/mrmime/zigbee.sock.

microvm.cloud-hypervisor.extraArgs = [
  "--user-device"
  "socket=zigbee.sock"
];

Of course, cloud-hypervisor needs to be told to add a device using that socket. microvm.nix doesn't have an option for this, so it needs to be done by just passing extra arguments.

usbvfiod = pkgs.usbvfiod.overrideAttrs rec {
  src = pkgs.fetchFromGitHub {
    owner = "cyberus-technology";
    repo = "usbvfiod";
    rev = "33ce5cab11ad93609472a173b7a83a890c3225b0";
    hash = "sha256-0SzQMYo9wvnI+UEPVv/ypJ/HEkA1MRywCYKutFti/NU=";
  };
  patches = [ ./fix-serial.patch ];
  cargoDeps = pkgs.rustPlatform.fetchCargoVendor {
    inherit src;
    hash = "sha256-WDqB6YVYjeCNZrGWhgc9ZjuMhadnaXv9oay0bEH/0sA=";
  };
};

The version of usbvfiod in nixpkgs doesn't actually work with the Zigbee adapter. The main branch improves support, and a patch from a WIP pull request get it functioning fine as far as I can tell.

{ pkgs, ... }: {
  microvm.vms.mrmime = {
    config = {
      <<config>>

      mjm.profiles.microvm = {
        enable = true;
        macAddress = "02:DB:5B:0A:7B:71";
        machineId = "0dfb2a79-d9ed-217d-66f2-c0f56824baac";
      };
      microvm.vsock.cid = 222;
      system.stateVersion = "25.05";
    };
  };

  <<host-config>>

  _class = "nixos";
}
Proxy Information
Original URL
gemini://midna.dev/homelab/hosts/artemis/mrmime.gmi
Status Code
Success (20)
Meta
text/gemini;lang=en-US
Capsule Response Time
15.221764 milliseconds
Gemini-to-HTML Time
0.074394 milliseconds

This content has been proxied by September (UNKNO).