Configure and control LEGO Powered Up train hubs over Bluetooth LE, directly on-device — no server/backend. BLE speaks the LEGO Wireless Protocol (LWP) v3 via SharpBrick.PoweredUp.
A Clean Architecture solution with two front-ends over one shared core: an Uno Platform app (App / HMI / Web) and a Spectre.Console CLI for a Raspberry Pi / Linux server.
Dependencies point inward; each layer only knows the ones to its left:
Domain ← Application ← Infrastructure ← Front-ends (HMI: CLI, Uno app = App/HMI/Web)
- Domain (
Trackify.Domain) — pure entities, enums, math. Depends on nothing (only the DI abstractions, contract-only). No UI, no logging, no EF, no BLE. - Application (
Trackify.Application) — use cases + ports (interfaces likeILegoService,ITrainRepository). Depends only on Domain. UI- and transport-agnostic. - Infrastructure (
Trackify.Infrastructure) — implements Application ports (EF Core + SQLite store, BlueZ hub transport). Depends on Application (+ Domain). - Front-ends (
Trackify.Cli,TrackifyUno app) — depend on Application; reference Infrastructure only at the composition root to wire concrete implementations into DI. - Never depend outward (Domain must not reference Application, Application must not reference
Infrastructure, …). Each layer owns its DI:
AddTrackifyDomain/Application/Infrastructure. - Enforced by the build: project references only point inward, and namespace-matches-folder
(
IDE0130) + file-scoped namespaces (IDE0161) are errors (Directory.Build.props).
| Project | Layer | Notes |
|---|---|---|
Source/Trackify.Domain |
Domain | Entities (Train, TrackSegment), enums, SpeedFunction |
Source/Trackify.Application |
Application | Ports, TrainControlService, LegoinoCatalog; hosts the mobile/WinRT ILegoService impls (multi-targeted per build host) |
Source/Trackify.Infrastructure |
Infrastructure | EF Core + SQLite store, BlueZ (Linux) transport |
Source/Trackify |
Front-end | Uno app — heads: android, ios, browserwasm (Web), desktop, windows |
Source/Trackify.Cli |
Front-end | Spectre.Console CLI for the Pi/Linux |
Test/Trackify.Tests |
Tests | xUnit, foldered by layer |
# Shared core + CLI + tests
dotnet build Source/Trackify.Cli/Trackify.Cli.csproj
dotnet test Test/Trackify.Tests/Trackify.Tests.csproj
# One Uno head (android / ios / browserwasm / desktop / windows)
dotnet build Source/Trackify/Trackify.csproj -f net10.0-desktopSDK: global.json pins 9.0.100 with rollForward: latestMajor — the newest installed major is
used (net10 heads require the .NET 10 SDK); CI provisions .NET 8, 9 and 10.
Trains are persisted in a SQLite database via EF Core (SqliteTrainRepository, repository-style
ITrainRepository; the schema is created automatically). Default location:
~/.config/Trackify/trackify.db (Linux) / %APPDATA%\Trackify\trackify.db (Windows), overridable
with the TRACKIFY_STORE environment variable. The Uno app and the CLI share the same schema.
trackify # dashboard (banner, saved trains, commands)
trackify discover # scan for hubs
trackify list # saved trains
trackify drive "Blauer Zug" --speed 40 --color Green # run until Ctrl+C
trackify stop "Blauer Zug"
trackify color "Blauer Zug" BlueSee Source/Trackify.Cli/ReadMe.md for deployment (Raspberry Pi, Docker, systemd autostart).
| Workflow | Trigger | Does |
|---|---|---|
ci.yml |
PR / push to master |
Build the CLI + shared core and run tests (pre-merge gate) |
android-apk.yml |
tag v* / manual |
Build the Android APK |
cli-arm64.yml |
tag v* / manual |
Publish the self-contained linux-arm64 CLI for the Pi |
Konfiguriert und steuert LEGO Powered Up Zug-Hubs über Bluetooth LE, direkt auf dem Gerät — kein Server/Backend. BLE spricht das LEGO Wireless Protocol (LWP) v3 über SharpBrick.PoweredUp.
Eine Clean-Architecture-Solution mit zwei Front-Ends über einem gemeinsamen Kern: eine Uno-Platform-App (App / HMI / Web) und eine Spectre.Console-CLI für Raspberry Pi / Linux-Server. Screenshots siehe oben.
Abhängigkeiten zeigen nach innen; jede Schicht kennt nur die links von ihr:
Domain ← Application ← Infrastructure ← Front-Ends (HMI: CLI, Uno-App = App/HMI/Web)
- Domain (
Trackify.Domain) — reine Entities, Enums, Mathematik. Hängt von nichts ab (nur den DI-Abstraktionen, reiner Vertrag). Kein UI, kein Logging, kein EF, kein BLE. - Application (
Trackify.Application) — Use Cases + Ports (Interfaces wieILegoService,ITrainRepository). Hängt nur von Domain ab. UI- und transport-neutral. - Infrastructure (
Trackify.Infrastructure) — implementiert die Application-Ports (EF-Core-+- SQLite-Store, BlueZ-Hub-Transport). Hängt von Application (+ Domain) ab. - Front-Ends (
Trackify.Cli,Trackify-Uno-App) — hängen von Application ab; referenzieren Infrastructure nur im Composition Root, um konkrete Implementierungen ins DI zu hängen. - Nie nach außen abhängen (Domain darf Application nicht kennen, Application nicht Infrastructure
…). Jede Schicht besitzt ihr DI:
AddTrackifyDomain/Application/Infrastructure. - Vom Build erzwungen: Projektverweise zeigen nur nach innen, und Namespace-passt-zu-Ordner
(
IDE0130) + file-scoped Namespaces (IDE0161) sind Fehler (Directory.Build.props).
| Projekt | Schicht | Hinweise |
|---|---|---|
Source/Trackify.Domain |
Domain | Entities (Train, TrackSegment), Enums, SpeedFunction |
Source/Trackify.Application |
Application | Ports, TrainControlService, LegoinoCatalog; enthält die Mobile-/WinRT-ILegoService-Impls (multi-targeted je nach Build-Host) |
Source/Trackify.Infrastructure |
Infrastructure | EF-Core-+-SQLite-Store, BlueZ-Transport (Linux) |
Source/Trackify |
Front-End | Uno-App — Heads: android, ios, browserwasm (Web), desktop, windows |
Source/Trackify.Cli |
Front-End | Spectre.Console-CLI für Pi/Linux |
Test/Trackify.Tests |
Tests | xUnit, nach Schicht in Ordner sortiert |
# Gemeinsamer Kern + CLI + Tests
dotnet build Source/Trackify.Cli/Trackify.Cli.csproj
dotnet test Test/Trackify.Tests/Trackify.Tests.csproj
# Ein Uno-Head (android / ios / browserwasm / desktop / windows)
dotnet build Source/Trackify/Trackify.csproj -f net10.0-desktopSDK: global.json pinnt 9.0.100 mit rollForward: latestMajor — das höchste installierte Major
wird genutzt (net10-Heads brauchen das .NET-10-SDK); die CI stellt .NET 8, 9 und 10 bereit.
Züge werden in einer SQLite-Datenbank über EF Core persistiert (SqliteTrainRepository,
Repository-artiges ITrainRepository; das Schema wird automatisch angelegt). Standardpfad:
~/.config/Trackify/trackify.db (Linux) / %APPDATA%\Trackify\trackify.db (Windows), überschreibbar
per Umgebungsvariable TRACKIFY_STORE. Uno-App und CLI teilen dasselbe Schema.
trackify # Dashboard (Banner, gespeicherte Züge, Befehle)
trackify discover # nach Hubs scannen
trackify list # gespeicherte Züge
trackify drive "Blauer Zug" --speed 40 --color Green # fahren bis Ctrl+C
trackify stop "Blauer Zug"
trackify color "Blauer Zug" BlueDeployment (Raspberry Pi, Docker, systemd-Autostart) siehe Source/Trackify.Cli/ReadMe.md.
| Workflow | Auslöser | Zweck |
|---|---|---|
ci.yml |
PR / Push auf master |
CLI + gemeinsamen Kern bauen und Tests laufen lassen (Pre-Merge-Gate) |
android-apk.yml |
Tag v* / manuell |
Android-APK bauen |
cli-arm64.yml |
Tag v* / manuell |
Self-contained linux-arm64-CLI für den Pi veröffentlichen |


