Architecture
GrowRig separates the user experience, grow-domain logic, device compatibility, networking, and physical control into distinct roles.
Grow App Web ─┐ ┌─ Home Assistant ─ third-party devices ├─ Grow Core ────────┤Grow App ─────┘ │ └─ MQTT broker ──── Grow Controller ─ fans / sensors / lights (Mobile) └─ External integrations ─ AI · weather · notificationsGrow 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, with the grow domain and its supporting catalogs beside it:
growcore/internal/├── config/ # YAML config: modes, adapters, device topology & entity bindings├── domain/ # semantic model: environment, device, role — plus grow, plant,│ # cultivar, care, feeding, inventory, integration, ai├── control/ # pure control law + reconciliation loop + Adapter interface├── sim/ # simulator adapter├── ha/ # Home Assistant adapter (WebSocket state + REST commands)├── catalog/ # device & vendor catalog (devices/ + vendors/)├── species/ # crop definitions: stages, cultivar attributes, care actions├── inventory/ # inventory categories + product templates├── feeding/ # nutrient schedules (feeding recipes)├── integrations/ # external-service bundles, encrypted secrets, capability runtimes├── camera/ # camera bindings and snapshot archive├── store/ # SQLite persistence├── webui/ # serves the embedded Grow App Web build└── api/ # HTTP + WebSocket (auth, per-environment access control)Adapters 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.
Two layers sit beside the physical control loop. The cultivation layer (grows & plants, inventory) tracks what you grow and the supplies you use, independent of any single tent. External integrations (bundles, instances, bindings) connect features like the AI assistant to outside services. Both are deliberately separate from adapters and devices, so a slow or absent AI provider, weather feed, or notification channel never affects climate control.
Grow Core also serves the Grow App Web build directly (the webui package), so a
single binary provides the API, the WebSocket, and the dashboard. Access is
multi-user: requests are authenticated (password or passkey), an admin role gates
configuration, and list responses are filtered per user with per-environment
read/write checks.
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”Grow App Web (SvelteKit) is the primary interface — dashboards, configuration and role mapping, the grow and plant records, the care journal, inventory, recipe editing, integrations, historical analysis, and diagnostics. Grow Core serves its build directly, so there is no separate web server to run. A future Grow App Mobile (Flutter) covers daily status, alerts, pairing, 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 | Users & access, semantic roles, environments, grows & plants, cultivars, care journal, inventory, feeding recipes, integration instances & secrets, control policies, cycle history, alerts, diagnostics. |
| Grow Controller | Current local outputs, safety state, last accepted policy, offline behavior, hardware health. |
| External services | The work behind a bound capability — model inference (AI), weather data, notification delivery. |
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.