Alexei Rojas Quiroga
← All projects

Personal project

SmartValue Monitor

Solar and battery dashboard built on a reverse-engineered inverter cloud API

Status
Live
Role
Solo: protocol analysis, backend API, frontend, persistence design, deployment
Live site GitHub

Architecture

  • One codebase, two deployments
  • Reverse-engineered vendor API
  • Hourly battery simulation
  • No passwords stored
  • Supabase with RLS

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
WHAT I BUILTReact · Next.jsSolar dashboardLive power, SOC,settings, forecastDockerPrivate self-hostingSame app on port 3000Cloudflare Pag…Public edge entryApp-router entry,public modeNext.js routeSettings APIUser and systemsettingsNext.js route …Solar forecastBattery SOC simulationNext.js routeDevice data APIAuth, device data,historySupabase Postg…Readings andsettings storeRLS tables, readings,settings RPCREST APIVendor cloudTelemetry and devicequeryWi-Fi dongleInverter dataloggerPushes telemetry overTCPOpen-MeteoWeather forecastHourly and dailyirradiance1234
  • 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.

Tech stack

Languages
TypeScriptPython
Frontend
React 19vinext (Next.js on Vite)Tailwind CSS
Cloud
Cloudflare Pages + Workers
Data
Supabase (PostgreSQL, RLS)Drizzle ORM
DevOps
Docker Compose
Testing
Node test runner