System Diagrams¶
Visual representations of the GreenThumb system architecture.
Hardware Setup¶
graph TB
subgraph "Raspberry Pi 5"
RPI[Raspberry Pi 5]
GPIO[GPIO/I2C]
USB[USB Port]
end
subgraph "Sensors"
AHT[AHT10<br/>Temp/Humidity]
BMP[BMP280<br/>Pressure/Temp]
TSL[TSL2561<br/>Light]
end
subgraph "Actuators"
CAM[USB Camera]
LED[RGB LED Strip]
PUMP[Water Pump]
end
GPIO --> AHT
GPIO --> BMP
GPIO --> TSL
USB --> CAM
GPIO --> LED
GPIO --> PUMP
Docker Services¶
graph LR
subgraph "Pi Docker Network"
DB[(PostgreSQL\n:5432)]
API[microcontroller-api\n:8080]
CTRL[controller]
DASH[local-dashboard\n:80]
WT[watchtower]
end
subgraph "External"
DH[Docker Hub]
BROWSER[User Browser]
end
CTRL -->|HTTP| API
DASH -->|HTTP proxy| API
API --> DB
BROWSER --> DASH
BROWSER --> API
DH --> WT
WT -->|rolling restart| API
WT -->|rolling restart| CTRL
Database Schema¶
erDiagram
DEVICE ||--o{ DEVICE_SENSOR : has
DEVICE ||--o{ DEVICE_ACTUATOR : has
DEVICE ||--o{ CULTIVATION : hosts
SENSOR_MODEL ||--o{ DEVICE_SENSOR : defines
SENSOR_MODEL ||--o{ SENSOR_CAPABILITY : has
ACTUATOR_MODEL ||--o{ DEVICE_ACTUATOR : defines
VARIABLE ||--o{ SENSOR_CAPABILITY : measured_by
VARIABLE ||--o{ MEASUREMENT : records
DEVICE_SENSOR ||--o{ MEASUREMENT : produces
PLANT_SPECIES ||--o{ CULTIVATION : grows
CULTIVATION ||--o{ THRESHOLD : has
UNIT ||--o{ VARIABLE : default_for
DEVICE {
int id_device PK
string name
string mac_address
string location
timestamp created_at
}
SENSOR_MODEL {
int id_sensor_model PK
string model_name
string manufacturer
}
ACTUATOR_MODEL {
int id_actuator_model PK
string model_name
string manufacturer
}
DEVICE_SENSOR {
int id_device_sensor PK
int id_device FK
int id_sensor_model FK
string port_address
boolean is_active
}
DEVICE_ACTUATOR {
int id_device_actuator PK
int id_device FK
int id_actuator_model FK
json config
boolean is_active
}
VARIABLE {
int id_variable PK
string name
string description
int default_unit_id FK
}
MEASUREMENT {
int id_measurement PK
timestamp collected_at
float value
int id_device_sensor FK
int id_variable FK
}
THRESHOLD {
int id_threshold PK
int id_cultivation FK
int id_variable FK
float min_value
float max_value
float target_value
int id_actuator_action FK
}
PLANT_SPECIES {
int id_plant_species PK
string name
string scientific_name
}
CULTIVATION {
int id_cultivation PK
int id_device FK
int id_plant_species FK
timestamp start_date
timestamp end_date
}
CI/CD Pipeline¶
graph LR
subgraph "Developer"
DEV[Push to main]
end
subgraph "GitHub Actions"
BUILD[Build Docker Images]
PUSH[Push to Docker Hub]
end
subgraph "Docker Hub"
API_IMG[microcontroller-api:latest]
CTRL_IMG[microcontroller-api-client:latest]
end
subgraph "Raspberry Pi"
WT[Watchtower]
CONTAINERS[Running Containers]
end
DEV --> BUILD
BUILD --> PUSH
PUSH --> API_IMG
PUSH --> CTRL_IMG
API_IMG --> WT
CTRL_IMG --> WT
WT --> CONTAINERS
Control Loop (Sense-Think-Act)¶
sequenceDiagram
participant CTRL as Controller
participant API as microcontroller-api
participant HW as Hardware
participant DB as PostgreSQL
Note over CTRL: Every 15 seconds
rect rgb(200, 230, 200)
Note over CTRL,API: SENSE
CTRL->>API: GET /state/
API->>HW: Read all sensors
HW-->>API: Sensor values
API->>DB: Load thresholds
DB-->>API: Threshold data
API-->>CTRL: SystemState
end
rect rgb(200, 200, 230)
Note over CTRL: THINK
Note over CTRL: Compare values vs thresholds
Note over CTRL: Determine actions
end
rect rgb(230, 200, 200)
Note over CTRL,HW: ACT
CTRL->>API: POST /state/actuators/{id}/command
API->>HW: Set actuator state
HW-->>API: OK
API-->>CTRL: OK
end
CTRL->>API: POST /state/heartbeat
Cloud Integration¶
Each Pi node syncs to a shared cloud backend over HTTPS. The cloud uses Supabase PostgreSQL for the fleet database and Supabase Storage for photos.
graph TB
subgraph "Greenhouse 1"
RPI1[Raspberry Pi]
DB1[(Local PostgreSQL)]
end
subgraph "Greenhouse 2"
RPI2[Raspberry Pi]
DB2[(Local PostgreSQL)]
end
subgraph "Cloud"
GW[Gateway :80]
GAPI[greenthumb-api :8000]
AUTH[auth-service :8081]
ACC[account-service :8082]
SUPDB[(Supabase PostgreSQL)]
SUPSTORAGE[Supabase Storage\nplant-photos]
end
subgraph "Admin"
ADMINDASH[Admin Dashboard :5173]
end
RPI1 -->|HTTPS sync| GW
RPI2 -->|HTTPS sync| GW
GW --> GAPI
GW --> AUTH
GW --> ACC
GAPI --> SUPDB
GAPI --> SUPSTORAGE
AUTH --> SUPDB
ACC --> SUPDB
ADMINDASH --> GW
Sync is best-effort and offline-safe: the Pi queues unsynced rows locally and pushes them when connectivity is restored.