Skip to content

Controller redesign with automation runs and room history - #211

Merged
JulianKahnert merged 23 commits into
developfrom
feature/flowkit-controller-redesign
Oct 3, 2026
Merged

JulianKahnert merged 23 commits into
developfrom
feature/flowkit-controller-redesign

Conversation

@JulianKahnert

Copy link
Copy Markdown
Owner

Server

  • Server config is stored in the database; an existing /tmp/HomeAutomation-config.json is imported once on first start
  • AutomationRun is recorded per execution with its trigger and outcome, kept for 30 days; the insert runs alongside execute, so the latency to the first command is unchanged
  • Command log entries carry runId and status (executed, cacheHit, failed)
  • New endpoints /runs, /config/automations/{name}/runs and /entities/history/room; every API change is additive
  • MaintenanceAutomation is a no-op; entityItems retention is handled by DatabaseCleanupJob alone (90 days)

Controller

  • Tabs Overview, Rooms, Automations and Settings replace History and Actions
  • Automations show their runs, grouping, inline toggles and why MotionAtNight triggered
  • Timeline, daily and room charts for ventilation, on-duration, CO2 and daily max/mean
  • Native SwiftUI lists, tab bar and text styles; Controller no longer depends on HAImplementations

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
JulianKahnert marked this pull request as ready for review October 3, 2026 22:03
@JulianKahnert
JulianKahnert enabled auto-merge (squash) October 3, 2026 22:04
@JulianKahnert
JulianKahnert merged commit b781824 into develop Oct 3, 2026
4 checks passed
@JulianKahnert
JulianKahnert deleted the feature/flowkit-controller-redesign branch October 3, 2026 22:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant