← All writing

Following the sun with Laravel

How my solar experiment collects readings, saves them in Valkey and shares updates through Laravel Cloud, Reverb and React.

Since having solar panels and a battery installed, I’ve wanted to understand more of what happens to the electricity we generate. How much stays with us? How much do we share with the grid? What difference is it making over time?

That became an experiment on this site. A day in every ray, with electricity used at home in gold and exports reaching a little further in orange. The shape invites exploration; the figures underneath help explain it.

An illustrative sun with gold rays for household electricity use and orange tips for exports. These are illustrative shapes, not measured results.

The visual language, illustrated. The experiment itself uses recorded readings; household use is not a claim that every kWh came from solar.

It has also been a useful way to learn more about Laravel and Laravel Cloud. There are three steps behind the picture: collect the data, save a useful result, and share it with the page.

Collect once, share the result

Sigenergy supplies the solar, battery and household readings. Octopus supplies smart-meter history and tariffs. NESO supplies historical grid carbon intensity, helping us estimate the emissions associated with imported electricity.

Laravel makes those requests on the server, validates the responses and prepares the comparisons. Credentials and private financial inputs stay there.

Data flow: Sigenergy, Octopus and NESO feed scheduled Laravel collectors. Results are saved in Valkey. Laravel endpoints serve saved results to the page; after saving current readings, Laravel broadcasts them through Reverb and Echo. Inertia and React present the interface.

Opening the page reads our saved results. It doesn’t ask all three providers to do the work again. That keeps their response times out of the visitor’s initial page render and avoids multiplying provider requests as more people visit.

Giving the work a timetable

The collectors are Artisan commands - Laravel’s way of running application code from a terminal or the Cloud Commands panel.

For example:

php artisan energy:collect

Our schedule lives alongside the command definitions in routes/console.php:

Schedule::command('energy:collect')
    ->everyFiveMinutes()
    ->withoutOverlapping(2);

With collection enabled in the application and Cloud’s Scheduler switched on, Laravel Cloud runs the scheduled work. I can also run a command manually to initialise or troubleshoot a collection. These collectors don’t need a separate queue worker.

Two update cycles: current readings are scheduled every five minutes but cooldowns can skip a run. Twice daily, history runs at 06:00 and 18:00 UTC, carbon ten minutes later, and the archive twenty minutes later.

There is a deliberate limit on provider requests. Our five-minute cooldown runs from the end of each current-reading request, so it can skip the next scheduled slot and produce roughly ten-minute gaps. “Live” here means receiving the next collected reading, not second-by-second telemetry.

The sun diagram and payback use completed days and a twice-daily archive refresh. Older monthly checkpoints are reused, so an interrupted collection can resume without starting from scratch.

A shared home for the readings

Valkey holds the saved readings and calculated results. Laravel connects through its Redis-compatible driver.

The latest reading expires after two days and is marked old after fifteen minutes. Shorter history snapshots last 35 days. Archive checkpoints and detailed private evidence have no automatic expiry; private evidence is encrypted, with its own separate store.

Keeping something without an expiry is still different from backing it up. Long-term retention needs that additional care. When a collection fails, we retain the last good result rather than replace it with empty data.

Bringing an open page along

Inertia connects the Laravel application to its React pages. After a new current reading is saved, Reverb broadcasts it and Laravel Echo receives it in the browser. React updates the house illustration without a page reload or a browser polling loop.

The historical sun and payback currently load a saved archive on page entry; they don’t use that push connection.

I like being able to follow the connection all the way through: from something happening on our roof, to a recorded observation, to a picture someone can explore. The picture makes the work approachable. Understanding what sits behind it makes the experiment useful.

More from the notebook