bloombase/README.md
Stephan Kerkman 1fe2b9fad8 docs: add Pl@ntNet to README (features, env vars, data sources)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 13:18:59 +02:00

115 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PlantDB
A personal plant management web app built with Django 5, Bootstrap 5, and HTMX.
Track your plants, identify them by photo, and get care info auto-filled from the Perenual and Pl@ntNet APIs.
## Features
- **Plant identification** — upload a photo; Pl@ntNet identifies it, shows top matches with reference images, pre-fills name and species, and saves the Pl@ntNet reference image as the plant thumbnail
- **Species search** — search Perenual API by name; care data (watering, sunlight, pruning months) is auto-filled and cached locally
- **Plant list** — filterable by name and location
- **Plant detail** — shows care info, pruning status, and pruning history
- **Pruning log** — log a pruning event with date and notes via HTMX partial update
- **Pruning calendar** — all plants grouped by urgency: overdue, due this month, due next month, later
- **Dashboard** — plant count, overdue pruning count, and attention list
## Data model
```
Species — cached from Perenual API (common_name, scientific_name, watering,
sunlight, pruning_months, api_image_url, perenual_id)
Plant — your actual plant (name, location, is_indoor, pruning_months,
photo, notes, species FK)
PruningLog — pruning events (plant FK, pruned_on, notes)
```
`Plant.pruning_months` is a JSON list of integers (112). It defaults to the species value but can be overridden per plant.
## Tech stack
| Layer | Library |
|---|---|
| Framework | Django 5.2 |
| Frontend | Bootstrap 5.3 + HTMX 1.9 |
| Image handling | Pillow |
| HTTP client | requests |
| Server | Gunicorn + Nginx |
| Database | SQLite |
## Local development
```bash
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py runserver
```
Set `PERENUAL_API_KEY` in your environment to enable species search (free tier: 100 requests/day).
Run tests:
```bash
pytest
```
## Deployment (Docker)
The production stack runs as two containers: `web` (Gunicorn) behind `nginx`.
```bash
# On the host — first time
cp .env.example .env # fill in SECRET_KEY, PERENUAL_API_KEY, ALLOWED_HOSTS, CSRF_TRUSTED_ORIGINS
docker compose up -d --build
```
After code changes:
```bash
# Sync files from dev machine
rsync -av --exclude='*.pyc' --exclude='__pycache__' . dockerhost:/home/stephan/stacks/plantdb/
# Rebuild
ssh dockerhost "cd /home/stephan/stacks/plantdb && docker compose up -d --build web"
```
### Environment variables
| Variable | Required | Example |
|---|---|---|
| `SECRET_KEY` | yes | long random string |
| `DEBUG` | no | `False` |
| `ALLOWED_HOSTS` | yes | `localhost,127.0.0.1,dockerhost` |
| `CSRF_TRUSTED_ORIGINS` | yes (non-localhost) | `http://dockerhost:8083` |
| `PERENUAL_API_KEY` | no | `sk-...` |
| `PLANTNET_API_KEY` | no | `2b10...` (get at my.plantnet.org) |
`CSRF_TRUSTED_ORIGINS` is required when accessing the app on a non-standard port or hostname — Django 5 rejects POSTs without it.
### Volumes
| Volume | Purpose |
|---|---|
| `db` | SQLite database at `/app/data/db.sqlite3` |
| `media` | User-uploaded plant photos |
| `static` | Collected static files |
## Plant data sources — research notes
The app currently uses **Perenual** (free tier, 100 req/day) for species data. Other sources investigated:
| Source | Status | Verdict |
|---|---|---|
| **Perenual** | Active | Best structured care data (watering, sunlight, pruning months). Free tier sufficient for personal use; each species is cached after first lookup. |
| **OpenFarm** | Shut down April 2025 | Dead. GitHub repo is a Ruby/MongoDB app with no data dump. |
| **Trefle** | Active | Botanical taxonomy only — no care schedules. Not a replacement. |
| **Wikipedia API** | Active | Returns name, description, thumbnail. No structured care data. |
| **Pl@ntNet** | Active | Plant identification from photos. Free tier: 500 req/day. Used for the identify-by-photo flow; reference image saved as plant thumbnail. |
| **Google Knowledge Panel** | N/A | Has structured care data but scraping violates ToS and is technically brittle. |
### Future opportunity
Google's plant Knowledge Panels aggregate care data (watering frequency, sunlight, pruning) from sources like The Sill, Bloomscape, Gardenia.net, and others. A curated, structured plant care dataset — particularly one covering common garden plants in NW Europe — does not currently exist as a clean, accessible API. This could be a commercial opportunity: either licensing a dataset or building a plant care API as a product.