Unverified Commit fbf58220 authored by Ilan Joselevich's avatar Ilan Joselevich Committed by GitHub
Browse files

nixos/home-assistant-matter-hub: init (#513732)

parents b271fb1d 3128eb64
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -728,6 +728,7 @@
  ./services/home-automation/esphome.nix
  ./services/home-automation/evcc.nix
  ./services/home-automation/govee2mqtt.nix
  ./services/home-automation/home-assistant-matter-hub.nix
  ./services/home-automation/home-assistant.nix
  ./services/home-automation/homebridge.nix
  ./services/home-automation/matter-server.nix
+100 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:
let
  cfg = config.services.home-assistant-matter-hub;
  settingsFormat = pkgs.formats.json { };
  configFile = settingsFormat.generate "home-assistant-matter-hub.json" cfg.settings;
in
{
  meta.maintainers = with lib.maintainers; [
    kranzes
    marie
  ];

  options.services.home-assistant-matter-hub = {
    enable = lib.mkEnableOption "home-assistant-matter-hub, a Matter bridge for Home Assistant";

    package = lib.mkPackageOption pkgs "home-assistant-matter-hub" { };

    openFirewall = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = ''
        Whether to open the Matter commissioning ports (UDP/TCP 5540) in the
        firewall.
      '';
    };

    accessTokenFile = lib.mkOption {
      type = lib.types.externalPath;
      example = "/run/secrets/home-assistant-matter-hub-token";
      description = ''
        Path to a file containing a Home Assistant long-lived access token.
        The file is loaded as a systemd credential and read into
        `HAMH_HOME_ASSISTANT_ACCESS_TOKEN` at service start.
      '';
    };

    settings = lib.mkOption {
      type = lib.types.submodule {
        freeformType = settingsFormat.type;
        options = {
          homeAssistantUrl = lib.mkOption {
            type = lib.types.str;
            example = lib.literalExpression "config.services.home-assistant.config.homeassistant.internal_url";
            description = "HTTP URL of the Home Assistant instance to bridge.";
          };

          httpPort = lib.mkOption {
            type = lib.types.port;
            default = 8482;
            description = "Port the web interface listens on.";
          };
        };
      };
      default = { };
      example = lib.literalExpression ''
        {
          homeAssistantUrl = config.services.home-assistant.config.homeassistant.internal_url;
        }
      '';
      description = ''
        Configuration written to a JSON file and passed to
        `home-assistant-matter-hub start --config`. Keys use camelCase, matching
        the long-form CLI flags. See
        <https://riddix.github.io/home-assistant-matter-hub/getting-started/installation#23-configuration-options>
        for the full list of options.
      '';
    };
  };

  config = lib.mkIf cfg.enable {
    networking.firewall = lib.mkIf cfg.openFirewall {
      allowedTCPPorts = [ 5540 ];
      allowedUDPPorts = [ 5540 ];
    };

    systemd.services.home-assistant-matter-hub = {
      description = "Home Assistant Matter Hub";
      documentation = [ "https://riddix.github.io/home-assistant-matter-hub/" ];
      wantedBy = [ "multi-user.target" ];
      after = [ "network.target" ];

      script = ''
        export HAMH_HOME_ASSISTANT_ACCESS_TOKEN=$(systemd-creds cat HAMH_HOME_ASSISTANT_ACCESS_TOKEN)
        exec ${lib.getExe cfg.package} start --config=${configFile} --storage-location="$1"
      '';
      scriptArgs = "%S/home-assistant-matter-hub";

      serviceConfig = {
        LoadCredential = [ "HAMH_HOME_ASSISTANT_ACCESS_TOKEN:${cfg.accessTokenFile}" ];
        DynamicUser = true;
        StateDirectory = "home-assistant-matter-hub";
      };
    };
  };
}
+104 −0
Original line number Diff line number Diff line
{
  lib,
  stdenvNoCC,
  fetchFromGitHub,
  nodejs,
  pnpm_10,
  pnpmConfigHook,
  fetchPnpmDeps,
  makeWrapper,
}:

stdenvNoCC.mkDerivation (finalAttrs: {
  pname = "home-assistant-matter-hub";
  version = "2.0.41";

  src = fetchFromGitHub {
    owner = "RiDDiX";
    repo = "home-assistant-matter-hub";
    tag = "v${finalAttrs.version}";
    hash = "sha256-+W0HjULERuW+RY7938xGnEXwmCpkumLpUlZmvfuhX2Y=";
  };

  # The bundled cli.js imports transitive dependencies (e.g. @noble/curves)
  # directly, so we need a flat node_modules tree for Node's resolver to
  # find them.
  pnpmInstallFlags = [ "--shamefully-hoist" ];
  pnpmWorkspaces = [ "home-assistant-matter-hub..." ];
  pnpmDeps = fetchPnpmDeps {
    inherit (finalAttrs)
      pname
      version
      src
      pnpmInstallFlags
      pnpmWorkspaces
      ;
    fetcherVersion = 3;
    hash = "sha256-1DaR4q1QH07UR+EchfDI92bTdRY4C2IaGIRj426DURI=";
  };

  __structuredAttrs = true;
  strictDeps = true;

  # Workspace package.json files all carry "0.0.0"; the real version is
  # injected at release time via APP_VERSION (consumed by vite for the
  # frontend bundle and by the backend at runtime).
  env.APP_VERSION = finalAttrs.version;

  nativeBuildInputs = [
    nodejs
    pnpm_10
    pnpmConfigHook
    makeWrapper
  ];

  buildPhase = ''
    runHook preBuild

    pnpm --filter home-assistant-matter-hub... run build

    runHook postBuild
  '';

  installPhase = ''
    runHook preInstall

    mkdir -p $out/bin $out/share/apps/home-assistant-matter-hub

    tar -xf apps/home-assistant-matter-hub/package.tgz \
      --strip-components=1 \
      -C $out/share/apps/home-assistant-matter-hub

    # pnpm cannot recursively prune monorepos, so we follow pnpm's
    # recommendation of removing all node_modules and reinstalling
    # only the production dependencies we need.
    find . -name node_modules -type d -prune -exec rm -rf {} +
    pnpm install --offline --prod --filter-prod home-assistant-matter-hub --shamefully-hoist

    # Workspace symlinks under apps/home-assistant-matter-hub/node_modules use
    # relative paths into the top-level node_modules/.pnpm store, so we keep
    # the original directory layout under $out/share.
    mv node_modules $out/share/
    mv apps/home-assistant-matter-hub/node_modules $out/share/apps/home-assistant-matter-hub/

    makeWrapper ${lib.getExe nodejs} "$out/bin/home-assistant-matter-hub" \
      --add-flags "$out/share/apps/home-assistant-matter-hub/dist/backend/cli.js" \
      --set NODE_ENV production \
      --set APP_VERSION ${finalAttrs.version}

    runHook postInstall
  '';

  meta = {
    description = "Publish your home-assistant instance using Matter";
    homepage = "https://riddix.github.io/home-assistant-matter-hub/";
    changelog = "https://github.com/RiDDiX/home-assistant-matter-hub/releases/tag/v${finalAttrs.version}";
    license = lib.licenses.asl20;
    maintainers = with lib.maintainers; [
      kranzes
      marie
    ];
    mainProgram = "home-assistant-matter-hub";
    inherit (nodejs.meta) platforms;
  };
})