Managing PV parks: site controllers, inverters and remote updates

A photovoltaic park has thousands of panels but only a handful of computers that matter: the site controllers and data loggers that read inverters and meters, apply setpoints and report to the operator. Across ten or fifty parks, that is hundreds of Linux boxes in cabinets, behind firewalls, often on cellular links. Keeping them current is an operations problem, not a coding problem.
What goes wrong without a fleet tool
Teams start with SSH and a script. It works for ten sites. At fifty it breaks down: sites are behind NAT, credentials are shared, nobody knows which cabinet runs which version, and a failed copy leaves a controller half updated. Sooner or later there is a site that has not been touched in two years.
A device that connects out
With Tuna the controller connects out to the hub, so nothing at the site has to be opened up. Each controller is a named device in a fleet, and you can split fleets by park, by vendor or by hardware. The status page of any device is reachable through its own address, and a recorded remote shell is available when you really need one.
Releases for protocols and drivers
A typical site release contains a Modbus reader, a protocol gateway and a local buffer so that no data is lost during a link outage:
{"services": {
"buffer": {"command": "./buffer/run.sh", "cwd": "volume"},
"modbus": {"command": "./modbus/run.sh", "dependsOn": ["buffer"], "healthPath": "/health", "port": 7001},
"gateway": {"command": "./gateway/run.sh", "dependsOn": ["buffer"], "healthPath": "/health", "port": 7002}}}
The local buffer lives on the data volume, so updating the gateway never loses the measurements waiting to be sent.
Change one park first
Mark the controllers of your smallest park as canaries. New releases reach them first, and you widen from there. A health check that fails on the first site stops the rollout before it reaches the others, and the controller that failed has already gone back to its previous release.
Per-site values without per-site builds
Plant capacity, grid operator endpoints and curtailment limits differ by site. Keep one release and give each device its own environment variables, with fleet defaults for the common ones. You can see at a glance which sites have overridden a default.
See the whole estate
The fleet view groups every controller with its status: working, updating, silent or never connected. A controller that goes quiet is visible within minutes, and you can be notified rather than discovering it from missing production data at month end.