Files
truetype b078b850f8 Initial commit: ShellyDash dashboard fotovoltaico
Flask app con gauge Chart.js custom, polling Shelly Cloud API v2,
storico SQLite, due widget gauge (produzione/consumo) con scala graduata.
2026-07-14 20:38:18 +02:00

3.5 KiB

shellydash — AGENTS.md

Quick start

cd /home/codex/shellydash
venv/bin/python3 app.py          # avvia su 0.0.0.0:5050

Il .env carica automaticamente via load_dotenv() in app.py e poller.py.

Stack

  • Python 3.14, Flask 3.1, SQLite, Chart.js 4.4 (CDN)
  • Venv: venv/ (già creato)
  • Dipendenze: flask, requests, python-dotenv

Architettura

File Ruolo
app.py Entrypoint Flask, 6 route API + serve templates/index.html
shelly_client.py Chiamate HTTP POST a Shelly Cloud Control API v2
database.py SQLite with WAL mode, schema readings, energy aggregations
poller.py Thread background: poll Shelly ogni 15s → insert DB + cache latest_parsed
templates/index.html Dashboard HTML + JS (Chart.js gauge custom plugin, storico, energia)

Flusso dati

Shelly Cloud ← poller.poll_once() (ogni 15s) → database.py (SQLite)
                                               → app._latest_parsed (dict, in-memory)
                                               → /api/status (da cache, non DB)
                                               → /api/history (da DB)

API endpoints

Route Descrizione Fonte dati
GET /api/status Letture live (produzione, consumo, delta, V, A, PF, temp) cache poller
GET /api/history?hours=24 Array timestamp → produzione/consumo DB
GET /api/energy/today Energia odierna (prodotta, consumata, immessa) DB (differenza energy counter)
GET /api/energy/monthly Breakdown giornaliero mese corrente DB
GET /api/delta Surplus/deficit booleano per automazioni cache poller

Shelly EM — assetto canali

  • Un solo device con ID d885ac0b5860 (Shelly EM Gen3, modello S3EM-002CXCEU)
  • em1:0 → produzione pannelli (pinza sull'uscita inverter)
  • em1:1 → consumo casa/rete (pinza sull'ingresso inverter, valori negativi = prelievo)
  • consumption_w nelle API = abs(ch1) quando negativo
  • Auth via auth_key (parametro query ?auth_key=...), non email/password
  • Endpoint: https://shelly-255-eu.shelly.cloud/v2/devices/api/{action}

Convenzioni codice

  • from __future__ import annotations in ogni .py
  • Type hints ovunque
  • Logging via logging.getLogger("shellydash.*")
  • .env non tracciato in git (.gitignore lo esclude)

Frontend (index.html)

  • Non usa framework JS — vanilla JS con Chart.js via CDN
  • Gauge semi-circolare con lancetta: plugin Chart.js custom (gaugePlugin), non libreria esterna
  • Due widget gauge: #gaugeProd (produzione, max 6000W, verde) e #gaugeCons (consumo, max 3000W, ambra)
  • Scala graduata con tacche maggiori (1000W) e minori (500W) disegnate su canvas
  • Auto-refresh ogni 15s via setInterval(refreshAll, 15000)
  • UI in italiano, tema scuro (#0f172a sfondo)

Comandi utili

# Avviare
venv/bin/python3 app.py

# Test API singola
curl -s http://localhost:5050/api/status | python3 -m json.tool

# Verificare import (senza avviare server)
venv/bin/python3 -c "from app import app; print('ok')"

# Installare nuove dipendenze
venv/bin/pip install <package>
# E aggiungere a requirements.txt

Note operative

  • Il poller parte in un thread dopo il primo poller.poll_once(). Serve almeno un poll riuscito prima che /api/status risponda.
  • Il DB è in data/shellydash.db — escluso da git.
  • POLL_INTERVAL in .env (default 15s).
  • Non ci sono test (repo in fase iniziale).
  • Il device Shelly deve essere online e connesso al cloud.