The dashboard calls /api/smartvalue; the backend authenticates against the vendor cloud, reads live device data (fed by the dongle) and stores an idempotent reading when persistence is on.
Architecture · 10 nodes · 4 flows
1Solar dashboard → Public edge entryHTTPS requests
Service / compute
Data store
Client
External system
Synchronous
Async / loop
Scroll sideways to see the full diagram
How it flows, step by step
Click a step to jump to it. Click a component for details.
What it does
A web dashboard for a home solar/battery system that uses SmartValue inverters. It signs in to the vendor's ValueClouds service, shows live power data and simulates battery state of charge against a weather-based solar forecast to tell the owner how much extra load is safe to run.
The problem
The vendor's mobile app is the only way to see the system, and the Wi-Fi dongle does not expose telemetry locally. Owners lack a shareable web view and any forecast of whether the battery will last the night.
What I built
Reverse-engineered the vendor APK and documented how the dongle talks to the cloud (TCP datalogger to m2m host, REST API for the app), then built a client for it.
Hour-by-hour battery simulation with charge/discharge efficiency, reserve limits and scenarios, exposed as a forecast API that computes safe extra load.
Zero-knowledge-style multi-user persistence: accounts are stored only as HMAC-SHA-256 fingerprints and passwords are never persisted.
Supabase tables use RLS with no anon/authenticated policies; only the backend holds the service-role key, and settings are saved through a transactional RPC.
Idempotent reading ingestion keyed by a deterministic SHA-256 ingestion key, with automated tests for the persistence layer.
Deployable two ways from one codebase: Docker container for private use or a Cloudflare Pages worker in public mode.
Key decisions and why
01
Use the vendor's cloud API instead of local telemetry
Analysis showed the dongle only pushes data outbound to the vendor cloud, so the simplest reliable source is the same REST API the app uses; a TCP decoder was kept as a vendor-independent alternative.
02
Public mode ignores server-side credentials
With SMARTVALUE_PUBLIC_MODE the backend refuses preconfigured credentials so a shared deployment can never expose the owner's account; each visitor signs in with their own.
03
Pseudonymous identity via HMAC fingerprint
Persisting history per user needs a stable key without storing the account in clear. A secret-keyed HMAC of the normalized account gives that, at the cost of making secret rotation a controlled migration.
04
Persistence is optional and backend-only
Without Supabase variables the monitor still works with temporary settings; the browser never talks to the database, which keeps the service-role key out of client code.