|
1 | 1 | # Solisdash |
2 | 2 |
|
3 | | -Self-hosted web dashboard for the SolisCloud (Ginlong Solis) platform. |
| 3 | +[](https://github.com/jdrumgoole/solisdash/actions/workflows/ci.yml) |
4 | 4 |
|
5 | | -Hybrid live tiles + historical charts. Shared SolisCloud key, simple multi-user login. |
| 5 | +Self-hosted web dashboard for the [SolisCloud](https://www.soliscloud.com/) (Ginlong Solis) platform. Live tiles on top, historical charts and an alarm feed below. FastAPI + HTMX + Jinja2 + Pico CSS, MongoDB-backed, with an in-process APScheduler poller. |
| 6 | + |
| 7 | +## What you get |
| 8 | + |
| 9 | +- **Live tiles** — current power, today's yield, this-month yield, battery SOC, open alarms. Refreshed every 30 s via HTMX; falls back to the most recent stored sample when SolisCloud rate-limits. |
| 10 | +- **History charts** — day (5-min granularity), month (daily totals), year (monthly totals), all-time (yearly totals). Reads MongoDB only, no upstream calls on the chart path. |
| 11 | +- **CSV export** for any chart view. |
| 12 | +- **Alarm feed** paginated and filterable by station + state. |
| 13 | +- **In-process poller** (APScheduler) that pulls `stationDetail` every 5 min and alarms on the same cadence, plus a nightly daily-rollup job at 00:30 UTC. Rate-limited via a shared `TokenBucket`. |
| 14 | +- **Session-cookie auth** (bcrypt) with an `invoke add-user` CLI. |
| 15 | +- **`/health`** (liveness) and **`/ready`** (Mongo + scheduler) probes. |
| 16 | +- **Dark-mode toggle** that persists per-browser. |
6 | 17 |
|
7 | 18 | ## Quick start |
8 | 19 |
|
| 20 | +1. `cp .env.example .env` and fill in: |
| 21 | + - `SOLIS_KEY_ID` / `SOLIS_KEYSECRET` from SolisCloud → Account → Basic Settings → API Management. |
| 22 | + - `SOLIS_API_URL` — the region-specific base URL (EU: `https://www.soliscloud.com:13333`). |
| 23 | + - `SOLIS_MONGODB_URI` — a non-prod MongoDB Atlas cluster. |
| 24 | + - `SESSION_SECRET` — generate with `python -c "import secrets; print(secrets.token_urlsafe(32))"`. |
| 25 | + - Optional: `RUN_SCHEDULER=true` to enable the in-process poller, `SOLIS_STATION_ID` to pin the dashboard to one station. |
| 26 | +2. `uv sync --extra dev` |
| 27 | +3. Seed your first admin: `uv run python -m invoke add-user --username you --role admin` |
| 28 | +4. `uv run python -m invoke start` — runs detached, log at `var/uvicorn.log`, lifecycle via `stop` / `restart` / `status`. |
| 29 | +5. Visit http://127.0.0.1:8000. |
| 30 | + |
| 31 | +## Pages |
| 32 | + |
| 33 | +| Path | Notes | |
| 34 | +| --- | --- | |
| 35 | +| `/` | Live tile dashboard (auth-gated). | |
| 36 | +| `/history` | Day / month / year / all-time charts with a download-CSV link. | |
| 37 | +| `/alarms` | Filterable alarm feed (auth-gated). | |
| 38 | +| `/login`, `/logout` | Session cookie auth. | |
| 39 | +| `/health`, `/ready` | Liveness + readiness probes. | |
| 40 | + |
| 41 | +## Invoke tasks |
| 42 | + |
9 | 43 | ``` |
10 | | -cp .env.example .env # edit with your SolisCloud key + Atlas URI |
11 | | -uv sync |
12 | | -uv run python -m invoke start |
| 44 | +uv run python -m invoke start # detached uvicorn |
| 45 | +uv run python -m invoke stop / restart / status |
| 46 | +uv run python -m invoke test # full suite under pytest-xdist |
| 47 | +uv run python -m invoke lint # ruff + mypy |
| 48 | +uv run python -m invoke add-user --username … --role admin|user |
| 49 | +uv run python -m invoke poll-once # one-shot stationDetail pull |
| 50 | +uv run python -m invoke backfill --start YYYY-MM-DD --end YYYY-MM-DD |
13 | 51 | ``` |
14 | 52 |
|
15 | | -App listens on http://127.0.0.1:8000. Health check at `/health`. |
16 | | - |
17 | 53 | ## Layout |
18 | 54 |
|
19 | | -- `src/solisdash/` — application package. |
20 | | -- `tests/` — pytest suite (parallel-safe under `pytest-xdist`). |
21 | | -- `tasks.py` — invoke build/admin tasks: `start`, `stop`, `restart`, `status`, `test`, `lint`. |
22 | | -- `tasks/todo.md` — current build plan. |
23 | | -- `CLAUDE.md` — project conventions for Claude Code sessions. |
24 | | -- `SolisCloud Platform API Document V2.0.3.pdf` — upstream API spec (source of truth). |
| 55 | +- `src/solisdash/` — application package |
| 56 | + - `app.py` — FastAPI app, lifespan, routes |
| 57 | + - `client.py` — async SolisCloud client (HMAC-SHA1 signing, retry/backoff) |
| 58 | + - `signing.py` — HMAC-SHA1 signing helper, pinned to the V2.0.3 worked example |
| 59 | + - `db.py` — Mongo connection + index schema |
| 60 | + - `auth.py` — bcrypt hashing, session helpers, FastAPI deps |
| 61 | + - `config.py` — pydantic-settings facade |
| 62 | + - `tiles.py`, `history.py`, `alarms.py` — page-specific services |
| 63 | + - `poller.py`, `ratelimit.py`, `scheduler.py` — APScheduler poller + token bucket |
| 64 | + - `templates/`, `static/` — Jinja2 + Pico CSS |
| 65 | +- `tests/` — pytest suite (160 tests, parallel-safe under `pytest-xdist`) |
| 66 | +- `tasks.py` — invoke build/admin tasks |
| 67 | +- `tasks/todo.md` — build plan (every step ticked through Polish) |
| 68 | +- `CLAUDE.md` — project conventions for Claude Code sessions |
| 69 | +- `SolisCloud Platform API Document V2.0.3.pdf` — upstream API spec (source of truth) |
| 70 | + |
| 71 | +## Development |
| 72 | + |
| 73 | +``` |
| 74 | +uv run python -m invoke lint # ruff + mypy |
| 75 | +uv run python -m invoke test # pytest -n auto |
| 76 | +``` |
| 77 | + |
| 78 | +CI runs the same against a `mongo:7` service container in GitHub Actions on every push and PR to `main`. |
| 79 | + |
| 80 | +## License |
| 81 | + |
| 82 | +MIT. |
0 commit comments