commit adb33de0bd9bd1fab0f3869bae520ca201a8bba5
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2026-10-04T05:06:03Z |
| subject | HA App packaging |
commit adb33de0bd9bd1fab0f3869bae520ca201a8bba5
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2026-10-04T05:06:03Z
HA App packaging
---
.dockerignore | 11 ++++
Dockerfile | 27 ++++++++++
ha-app/CHANGELOG.md | 7 +++
ha-app/DOCS.md | 124 ++++++++++++++++++++++++++++++++++++++++++++
ha-app/README.md | 7 +++
ha-app/config.yaml | 29 +++++++++++
ha-app/run.sh | 40 ++++++++++++++
ha-app/translations/en.yaml | 19 +++++++
repository.yaml | 3 ++
scripts/stage-ha-app.sh | 37 +++++++++++++
10 files changed, 304 insertions(+)
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..8b17b93
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,11 @@
+*
+!go.mod
+!go.sum
+!cmd/
+!cmd/**
+!internal/
+!internal/**
+!ha-app/
+!ha-app/run.sh
+!LICENSE
+!NOTICE
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..ed2d680
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,27 @@
+# syntax=docker/dockerfile:1
+ARG GO_VERSION=1.26
+FROM golang:${GO_VERSION}-bookworm AS builder
+WORKDIR /src
+COPY go.mod go.sum ./
+RUN go mod download
+COPY cmd ./cmd
+COPY internal ./internal
+RUN CGO_ENABLED=0 go build -mod=readonly -buildvcs=false -trimpath \
+ -ldflags='-s -w' -o /out/homekey ./cmd/homekey
+
+FROM debian:bookworm-slim
+ARG BUILD_VERSION=0.0.1
+ARG BUILD_ARCH=amd64
+LABEL io.hass.type="app" \
+ io.hass.version="${BUILD_VERSION}" \
+ io.hass.arch="${BUILD_ARCH}" \
+ org.opencontainers.image.title="homekey-go" \
+ org.opencontainers.image.licenses="Apache-2.0"
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ ca-certificates jq tzdata && rm -rf /var/lib/apt/lists/*
+COPY --from=builder /out/homekey /usr/local/bin/homekey
+COPY ha-app/run.sh /usr/local/bin/homekey-entrypoint
+COPY LICENSE NOTICE /usr/share/doc/homekey-go/
+RUN chmod 0755 /usr/local/bin/homekey-entrypoint
+WORKDIR /data
+ENTRYPOINT ["/usr/local/bin/homekey-entrypoint"]
diff --git a/ha-app/CHANGELOG.md b/ha-app/CHANGELOG.md
new file mode 100644
index 0000000..7c5ae07
--- /dev/null
+++ b/ha-app/CHANGELOG.md
@@ -0,0 +1,7 @@
+# Changelog
+
+## 0.0.1
+
+- Package the existing HomeKit lock and Home Key provisioning service for HA OS.
+- Persist pairing identity, PIN, and credentials in /data/state.
+- Configure accessory identity, HAP port, LAN interface, and Wallet finish.
diff --git a/ha-app/DOCS.md b/ha-app/DOCS.md
new file mode 100644
index 0000000..4bc4e1c
--- /dev/null
+++ b/ha-app/DOCS.md
@@ -0,0 +1,124 @@
+# Home Key Go on Home Assistant OS
+
+## Local installation (no published image required)
+
+After adding these files to the root of the homekey-go source repository:
+
+```sh
+sh scripts/stage-ha-app.sh
+```
+
+Copy the resulting `dist/homekey_go` directory into HA OS's `/addons` directory,
+using the Samba `addons` share or an SSH app. The result must be
+`/addons/homekey_go/config.yaml`, alongside its Dockerfile and source directories.
+In HA, open Settings > Apps > App store, select Check for updates from the
+three-dot menu, then install Home Key Go under Local apps.
+On older HA versions the UI calls these Add-ons.
+
+Enable Start on boot, start the app, and open Logs. Use the pairing code printed
+by the Go service in Apple Home > Add Accessory > More Options > Go Home Key.
+The container image build downloads Go dependencies, including the patched HAP
+fork specified by go.mod. Internet access is needed during the initial build.
+
+## Configuration
+
+```yaml
+name: Go Home Key
+serial: GO-HOMEKEY-001
+port: 51826
+interface: ""
+finish: silver
+pin: ""
+```
+
+- `name`: accessory name shown in Apple Home.
+- `serial`: stable accessory serial; keep it unchanged after pairing.
+- `port`: HAP TCP port on the HA OS host. Change it if 51826 is occupied.
+- `interface`: HA OS LAN interface, e.g. `end0` or `enp3s0`; empty selects
+ eligible interfaces. Use the actual HA host interface name.
+- `finish`: `silver`, `black`, `gold`, or `tan` Wallet artwork.
+- `pin`: empty generates and saves a random PIN, then reuses it on later starts.
+ An explicit PIN must have eight digits (hyphens are accepted by the CLI);
+ prohibited HomeKit PIN patterns are rejected by the service.
+
+Save configuration changes and restart the app.
+The app uses host networking for HomeKit mDNS and binds HAP to `:<port>`.
+Your phone must be able to reach the HA host and receive its mDNS advertisements.
+
+## Persistent state and moving an existing pairing
+
+The service is started with `-state /data/state`. HomeKit identity, paired
+controllers, Home Key credentials, and the generated PIN are stored together
+in `/data/state/state.json`. This is the app's persistent data volume, not the
+HA configuration directory. App backups use cold mode so the service is stopped
+while its state is backed up.
+
+For a first installation you can pair a fresh accessory. To preserve an existing
+pairing from your Mac, stop the Mac service and the HA app, then copy the entire
+existing state directory into the app's `/data/state` through a method with
+access to that app's data volume. The ordinary `/addons` source folder and HA
+`/config` directory are NOT that volume. Keep the same name, serial, and explicit
+PIN, if one was configured. Run only one instance with that identity.
+
+Do not delete state or uninstall the app as an update procedure: losing the
+state means losing its pairing identity and credentials. Keep an app backup.
+
+## Building a container outside HA
+
+From the source repository root:
+
+```sh
+docker build -t homekey-go:0.0.1 .
+```
+
+On a Linux Docker host, run it with a persistent volume and host networking:
+
+```sh
+docker run --rm --network host -v homekey-state:/data homekey-go:0.0.1
+```
+
+Without `/data/options.json`, the CLI uses its default accessory settings with
+state fixed to `/data/state`. Explicit container arguments are passed directly
+to the CLI, so include `-state /data/state` when supplying custom arguments:
+
+```sh
+docker run --rm --network host -v homekey-state:/data homekey-go:0.0.1 \
+ -state /data/state -name 'Go Home Key' -addr :51827
+```
+
+Docker Desktop on macOS is not equivalent to a Linux HA OS host for LAN mDNS.
+Use HA OS for the actual discovery and pairing test.
+
+## Publishing and repository installation
+
+`ha-app/config.yaml` is set up to pull `ghcr.io/tgckpg/homekey-go:0.0.1`.
+That image has NOT been published by this packaging work. If you use another
+registry/namespace, edit its `image` field. Build and push both supported
+architectures before attempting repository installation:
+
+```sh
+docker login ghcr.io
+docker buildx build --platform linux/amd64,linux/arm64 \
+ --build-arg BUILD_ARCH='aarch64|amd64' \
+ --build-arg BUILD_VERSION=0.0.1 \
+ -t ghcr.io/tgckpg/homekey-go:0.0.1 --push .
+```
+
+Make the package public if HA will pull it without registry credentials.
+Commit the packaging files to a cloneable Git repository, then add its Git URL
+under App store > Repositories. Use the real Git repository endpoint, not the
+static `sgit` HTML tree URL. Supervisor pulls the image using `config.yaml`.
+The root `repository.yaml` declares this repository; `ha-app` contains the app.
+Once the image is published, those metadata files can instead live in your
+separate HA app repository; the root Dockerfile and Go source stay here.
+
+For releases, update the app version in config.yaml and CHANGELOG.md, build and
+publish the matching image tag, then commit the metadata. Preserve the app slug
+and repository identity to keep existing installs on their update path.
+
+## Current functionality
+
+This packages the existing provisioning service unchanged. The HAP listener
+supports Apple Home pairing and Home Key provisioning; lock toggles are still
+simulated. No reader API, MQTT connection, Home Assistant entity integration,
+or ESP32/PN532 authentication transport is added by these files.
diff --git a/ha-app/README.md b/ha-app/README.md
new file mode 100644
index 0000000..508f4d7
--- /dev/null
+++ b/ha-app/README.md
@@ -0,0 +1,7 @@
+# Home Key Go
+
+Virtual HomeKit lock with Apple Home Key provisioning, packaged for Home Assistant OS.
+See [DOCS.md](DOCS.md) for installation and configuration.
+
+This version provisions Home Key credentials and simulates lock state changes.
+It does not yet connect an ESP32/PN532 reader or operate a physical lock.
diff --git a/ha-app/config.yaml b/ha-app/config.yaml
new file mode 100644
index 0000000..f5f933d
--- /dev/null
+++ b/ha-app/config.yaml
@@ -0,0 +1,29 @@
+name: Home Key Go
+version: "0.0.1"
+slug: homekey_go
+description: Virtual HomeKit lock and Apple Home Key provisioning service
+url: https://sgit.k8s.astropenguin.net/penguin/homekey-go/
+arch:
+ - aarch64
+ - amd64
+startup: services
+boot: auto
+init: true
+host_network: true
+backup: cold
+stage: experimental
+image: ghcr.io/tgckpg/homekey-go
+options:
+ name: Go Home Key
+ serial: GO-HOMEKEY-001
+ port: 51826
+ interface: ""
+ finish: silver
+ pin: ""
+schema:
+ name: str(1,)
+ serial: str(1,)
+ port: port
+ interface: str
+ finish: list(silver|black|gold|tan)
+ pin: password
diff --git a/ha-app/run.sh b/ha-app/run.sh
new file mode 100755
index 0000000..7d953e4
--- /dev/null
+++ b/ha-app/run.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+set -eu
+umask 077
+
+# Explicit arguments are passed directly to the CLI (e.g. -status -state ...).
+if [ "$#" -gt 0 ]; then
+ exec /usr/local/bin/homekey "$@"
+fi
+
+set -- -state /data/state
+if [ -f /data/options.json ]; then
+ jq -e '
+ type == "object" and
+ (.name | type == "string" and length > 0) and
+ (.serial | type == "string" and length > 0) and
+ (.port | type == "number" and . == floor and . >= 1 and . <= 65535) and
+ (.interface | type == "string") and
+ (.finish | . == "silver" or . == "black" or . == "gold" or . == "tan") and
+ (.pin | type == "string")
+ ' /data/options.json >/dev/null || {
+ echo 'Invalid Home Key Go options; check the app configuration.' >&2
+ exit 1
+ }
+ name=$(jq -r '.name' /data/options.json)
+ serial=$(jq -r '.serial' /data/options.json)
+ port=$(jq -r '.port' /data/options.json)
+ iface=$(jq -r '.interface' /data/options.json)
+ finish=$(jq -r '.finish' /data/options.json)
+ pin=$(jq -r '.pin' /data/options.json)
+ set -- "$@" -name "$name" -serial "$serial" -addr ":$port" -finish "$finish"
+ if [ -n "$iface" ]; then
+ set -- "$@" -interface "$iface"
+ fi
+ if [ -n "$pin" ]; then
+ set -- "$@" -pin "$pin"
+ fi
+fi
+
+# exec lets the Go service receive SIGTERM and release its state lock.
+exec /usr/local/bin/homekey "$@"
diff --git a/ha-app/translations/en.yaml b/ha-app/translations/en.yaml
new file mode 100644
index 0000000..95437bc
--- /dev/null
+++ b/ha-app/translations/en.yaml
@@ -0,0 +1,19 @@
+configuration:
+ name:
+ name: Accessory name
+ description: Name shown in Apple Home.
+ serial:
+ name: Serial number
+ description: Stable accessory serial. Keep unchanged once paired.
+ port:
+ name: HomeKit port
+ description: TCP listen port on the HA OS host. Must be unused by other services.
+ interface:
+ name: LAN interface
+ description: Host network interface for mDNS. Leave empty for automatic selection.
+ finish:
+ name: Wallet artwork
+ description: Home Key appearance in Apple Wallet.
+ pin:
+ name: Pairing PIN
+ description: Leave empty to generate and save a PIN. Otherwise use eight digits.
diff --git a/repository.yaml b/repository.yaml
new file mode 100644
index 0000000..2b57656
--- /dev/null
+++ b/repository.yaml
@@ -0,0 +1,3 @@
+name: Penguin Home Key apps
+url: https://sgit.k8s.astropenguin.net/penguin/homekey-go/
+maintainer: Penguin
diff --git a/scripts/stage-ha-app.sh b/scripts/stage-ha-app.sh
new file mode 100755
index 0000000..c6e4553
--- /dev/null
+++ b/scripts/stage-ha-app.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Create a self-contained local app build context; source need not be committed.
+set -eu
+
+root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
+dest=${1:-"$root/dist/homekey_go"}
+
+if [ "$#" -gt 1 ]; then
+ echo 'Usage: sh scripts/stage-ha-app.sh [destination]' >&2
+ exit 1
+fi
+
+if [ -e "$dest" ]; then
+ echo "Destination already exists: $dest. Choose a new directory." >&2
+ exit 1
+fi
+
+mkdir -p "$dest"
+
+cp "$root/Dockerfile" "$root/.dockerignore" "$root/go.mod" "$root/go.sum" \
+ "$root/LICENSE" "$root/NOTICE" "$dest/"
+
+cp -R "$root/cmd" "$root/internal" "$dest/"
+
+mkdir -p "$dest/ha-app"
+
+cp "$root/ha-app/run.sh" "$dest/ha-app/run.sh"
+
+# Local installation builds the Dockerfile instead of pulling a published image.
+sed '/^image:/d' "$root/ha-app/config.yaml" > "$dest/config.yaml"
+
+cp "$root/ha-app/DOCS.md" "$root/ha-app/README.md" \
+ "$root/ha-app/CHANGELOG.md" "$dest/"
+
+cp -R "$root/ha-app/translations" "$dest/"
+
+printf 'Local app build context: %s\n' "$dest"