Repository navigation
Controller redesign with automation runs and room history - #211
Merged
Merged
Conversation
The config moves from /tmp/HomeAutomation-config.json into a single-row `config` table, imported once from the legacy file. Activating or deactivating an automation now persists, so the state survives restarts and container recreation. Retention lives in DatabaseCleanupJob only: MaintenanceAutomation no longer deletes entity history older than two days.
Every triggered automation now gets an AutomationRun row: what triggered
it (derived from the HomeEvent, optionally enriched by the automation),
when it started and ended, and whether it completed, was superseded,
stopped, failed or interrupted by a server restart. HealthCheck and
MaintenanceAutomation opt out via `recordsRuns`; MotionAtNight appends
the illuminance that let it trigger.
The API exposes GET /config/automations/{name}/runs and GET /runs, and
the automation list gains `type`, `recordsRuns`, `lastRun` and
`entities`. Runs are deleted after 30 days.
ActionLogItem gains `runId` and `status` (executed, cacheHit, failed). The run id travels as a task local from AutomationService into HomeManager and is carried explicitly through the detached retry loop. GET /actions accepts `runId` to list one run's commands.
GET /entities/history/room returns the history of every entity in a place. With `includePrevious`, the last state before startDate is appended as the oldest item, so a light that has been on since yesterday starts at the left edge of a timeline. GET /entities/history accepts `includePrevious` as well.
Add run, room history and health endpoints to the server client dependency, refresh all tabs through one refreshAll action, group automations by status or type with an optimistic toggle, and list a detail's devices and 24 h runs with a run detail showing the commands it sent.
…feed The overview polls the server every 30 s while visible: adapter health, open windows, running automations with a stop button, the last runs and notices derived from failed runs and failed commands. The feed merges runs and commands of the last 24 hours.
Entities are grouped by room with a symbol per characteristic. The entity chart draws on/off states as bars, uses a log axis for lux, starts from the state before the window and requests at most the API limit of 1000 items. The action log moves into Settings > Diagnostics as Command Log with status filters; open windows moved to the Overview.
StateIntervals, DailyTotals and RunStatistics turn history and runs into chart data in HAModels, testable on Linux. TimelineChart and ValueChart are the two chart views every chart is configured from; the room header in Rooms now opens a timeline of its lamps, motion sensors and windows.
Motion and light lanes above the illuminance curve with the trigger threshold and night bands, from the server location stored once from GET /config.
Room detail shows CO2 with a 1000 ppm threshold and open-window bands, plus ventilation minutes per day over 7 days. Entity detail in the 7-day range shows on-hours per day for lamps and daily max with time-weighted mean for lux and CO2.
The entity detail drew its own card list inside a ScrollView; it is now a List with sections. The custom capsule badge becomes a tinted SF Symbol label. Room devices show their name, and state lanes say Open/Motion instead of On for contacts and motion sensors.
The MotionAtNight debug chart only needs the lux threshold, so the constant moves to HAModels and the Controller stops linking every automation.
Swift 6 rejects mutating a captured var from the token callback; the iOS-only tests never built because CI runs them on macOS only.
Drop the sidebar-adaptable tab style and the bold/monospaced overrides. Open windows now say how long they are open and what the limit is, and run and command rows get full-width separators.
Checked every screen on the iPhone simulator in light and dark mode: - automation rows are plain toggles; a running automation says so in its subtitle - labeled rows no longer blow up when they hold a label with an icon - timeline charts use the Swift Charts legend instead of a hand-built one - time axes keep the last label visible and show weekdays for 7-day ranges - entity value charts reuse ValueChart; the daily chart labels max and mean in its legend - button rows in lists keep primary text and tint only the icon
The run insert was awaited before the execute task started, so the time from "motion detected" to the first light depended on the database. The run id is now created up front; the trigger summary and the insert run in a parallel task, and `finish` waits for that task so no update can reach the database before its insert.
… one effect Entity and run details are NavigationLink pushes instead of sheet destinations, the activity filter moves into a toolbar menu, and room rows inflect their device count instead of showing the raw markup. The history detail loads every page from a single cancellable effect. Paging through actions let a late page reach a screen that was already popped (TCA "missing element" warning) and append items of a previous time range after a refresh. Deprecated TCA `scope(state:action:)` and `Scope(state:action:child:)` calls use the renamed APIs.
…its device The devices of an automation came from a reflection over the whole object, so battery sensors no automation reads and devices held twice (the light sensor is usually one of the motion sensors) showed up. The server now sends `involvedEntityIds`, which drops both. The reflection also skipped every id of a device subclass such as `EveMotion`, because `Mirror` lists only the subclass's own properties; it now walks the `superclassMirror` chain. A run's trigger row opens the history of the device that fired it.
Activity feed entries and filter, room automations and time-range reloads, automation details (runs only when recorded, the MotionAtNight chart limited to the automation's devices, stop marks not running and reloads), the overview snapshot and stop, history time-range change and failure alert, and the automation type labels.
Tapping a row in the Running section switches to the Automations tab and opens that automation's details, the same way a run's Open Automation button does. The Stop button keeps its own action inside the row.
…el color Automation details list each device on two lines, "Eve Motion" over "Motion Sensor (Arbeitszimmer)", and the MotionAtNight chart labels its lanes with the room as well, so devices with the same name in different rooms no longer share a lane. The running row in the Overview tints the row button with the label color: `.primary` resolves relative to the tint inside a button label, so overriding the foreground style alone left the text accent-colored. The Stop button keeps the accent explicitly.
JulianKahnert
marked this pull request as ready for review
October 3, 2026 22:03
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Server
/tmp/HomeAutomation-config.jsonis imported once on first startAutomationRunis recorded per execution with its trigger and outcome, kept for 30 days; the insert runs alongsideexecute, so the latency to the first command is unchangedrunIdandstatus(executed,cacheHit,failed)/runs,/config/automations/{name}/runsand/entities/history/room; every API change is additiveMaintenanceAutomationis a no-op;entityItemsretention is handled byDatabaseCleanupJobalone (90 days)Controller
MotionAtNighttriggeredControllerno longer depends onHAImplementations