Keep solar and battery optimization local
A battery controller on an SBC in the utility closet reads inverter telemetry every few seconds, checks the day-ahead tariff curve, and decides whether to charge from the panels or the grid, without touching the internet. Not a chatbot problem. It's constrained optimization wearing a home-automation costume, with hard constraints: state-of-charge floors, charge-rate ceilings, inverter warranty limits. Get those wrong and you're debugging a bricked battery, not a software bug.
The four lines that decide if hardware is even needed
Write the event, the input, the output, and the deadline before you touch a board. "Shift load when it's cheap" is not a job. "When the next hour's price sits below the daily median and the battery covers the overnight draw, move the water heater into that hour" is testable, and it tells you if you even need a model. Most of this is arithmetic on a schedule, not inference.
Separate the hard inverter limits from the forecast-driven decisions, and simulate the whole loop before it writes to the inverter. Test against your own panel orientation and BMS, over whatever router you actually run: edge deployments amplify ordinary variation:
- a weak Wi-Fi hop to the inverter dropping telemetry mid-cycle
- a BMS reporting a stale state-of-charge after a cold night
- the tariff feed timing out and stalling the decision loop
- a growing Home Assistant database slowing every read
Keep a short record while you test, not after:
board / power supply / enclosure temperature
inverter model + firmware version
tariff feed + battery SoC source
decision latency, cold start vs warm
recovery behavior after a network drop
The charge command never comes from a sentence
The failure I've watched people walk into is letting a language model issue charge or discharge commands straight from a prompt. A model can rank options, summarize the day, explain why the battery didn't discharge as expected. It should never be the only thing between a request and a real amp draw. State-of-charge floors, C-rate ceilings, timeouts, permissions: deterministic code owns those. Any text the system reads is data, not instruction.
Running locally doesn't make this private by default. Logs and a remote dashboard can still carry copies of the same telemetry off-site. Decide what gets kept and for how long, or "local" is theater.
Thermal equilibrium is the only test that counts
Run it as a service with pinned versions, not a script someone remembers to restart. Config lives apart from the model files. The health check has to prove the loop is deciding something, not that a process owns a port. Let the enclosure run to thermal equilibrium under real load, then measure power at the wall. Throttling, swapping, corrupted storage: not ready, whatever the demo looked like.
The one rule I'd keep: deterministic code owns every safety and warranty limit, the model never gets a vote on those, only an explanation after.