Architecture
GrowRig separates the user experience, grow-domain logic, device compatibility, networking, and physical control into distinct roles.
Flutter App ┐ ├─ Grow Core ─┬─ Home Assistant ─ third-party devicesSvelteKit ──┘ └─ MQTT broker ──── Grow Controller ─ fans / sensors / lightsGrow Core
Section titled “Grow Core”Grow Core is the local backend and the source of truth for the grow domain. It is implemented in Go, stores data in SQLite, and exposes an HTTP + WebSocket API. It packages as a Home Assistant OS add-on or a Docker container.
At its heart it is a reconciliation engine:
actual state + desired targets + active phase + safety constraints ↓desired device stateThe engine is organised around a pure control law that is independent of any single adapter:
growcore/internal/├── config/ # YAML config: modes, adapters, device topology & entity bindings├── domain/ # semantic model: environment, device, channel, role├── control/ # pure control law + reconciliation loop + Adapter interface├── sim/ # simulator adapter├── ha/ # Home Assistant adapter (WebSocket state + REST commands)├── store/ # SQLite persistence└── api/ # HTTP + WebSocketAdapters implement the same Adapter interface, so the engine and the pure control
law behave identically whether devices are simulated or reached through Home
Assistant. New adapters (for example, direct MQTT) slot in behind the same interface
without touching domain logic.
Home Assistant
Section titled “Home Assistant”Home Assistant remains responsible for device discovery, third-party integrations, current device state, protocol translation, and generic notifications. Grow Core does not mirror Home Assistant internals into its own domain model — see Home Assistant integration and data ownership.
The apps
Section titled “The apps”The web app (SvelteKit) is for configuration, role mapping, hardware tests, recipe editing, historical analysis, diagnostics, and firmware flashing. A future Flutter app covers daily status, alerts, QR pairing, BLE provisioning, quick overrides, and journal photos.
Controller connectivity
Section titled “Controller connectivity”The prototype supports two paths to a controller.
Home Assistant path — the easiest DIY path:
Grow Controller → ESPHome native API → Home Assistant → Grow CoreDirect path — reduces coupling and keeps working while Home Assistant restarts:
Grow Controller → MQTT → Grow CoreESPHome can expose both. To avoid duplicate ownership, exactly one adapter is authoritative for commands; the other may remain available for visibility or migration.
Controller responsibility
Section titled “Controller responsibility”The Grow Controller handles the fast, safety-critical loop locally: PWM output, tachometer measurement, min/max speed, startup boost, command timeout, fallback state, emergency behavior, physical override, and the last valid policy. Grow Core sends intent and policy — it does not micromanage every PWM edge.
Data ownership
Section titled “Data ownership”| Owner | Owns |
|---|---|
| Home Assistant | Raw entity states, protocol connectivity, discovery, generic history. |
| Grow Core | Semantic roles, environments, recipes, control policies, cycle history, alerts, diagnostics. |
| Grow Controller | Current local outputs, safety state, last accepted policy, offline behavior, hardware health. |
Networking
Section titled “Networking”Grow devices sit behind a Grow Gateway on an isolated network. The recommended default policy denies grow devices access to the home LAN and the internet, allows the Hub selected outbound services, and allows the home LAN to reach the Grow App / HA UI. For now the Gateway can be any suitable Wi-Fi router.