Grid Lens requires Home Assistant 2024.1 or later with the following already working:
Solar, battery, and EV sensors are optional but unlock more accurate modelling.
Add the Grid Lens repository to HACS as a custom repository:
https://github.com/dankasak/gridlens with category IntegrationCopy the custom_components/grid_lens folder from the GitHub repo into your HA config/custom_components/ directory, then restart.
After restarting, go to Settings → Devices & Services → Add Integration and search for Grid Lens.
Setup is four short screens:
If your Energy dashboard lists individual appliances, you'll also get a screen to pick which of them can be shifted to cheaper hours, and set each one's maximum power.
Everything else — controlled load, allowed run hours, modulating charger control, battery efficiency and charge limits — has a sensible default and can be changed later under Grid Lens → Configure. Nothing you skip at setup is lost.
Grid Lens adds a Grid Lens dashboard to your Home Assistant sidebar automatically — no cards to add, no YAML. It has three views:
The cards find their own entities, so they keep working as you add, remove, or reconfigure loads.
Grid Lens needs at least one of the following entity types, already configured in your Energy dashboard:
| Sensor type | Required? | Notes |
|---|---|---|
| Grid consumption (kWh) | Required | Total energy drawn from grid |
| Grid export (kWh) | Optional | Needed for feed-in tariff modelling |
| Solar production (kWh) | Optional | Enables solar self-consumption analysis |
| Battery charge / discharge (kWh) | Optional | Enables battery optimisation |
| EV / deferrable load (kWh) | Optional | Enables load-shifting recommendations |
If trees or a neighbouring roofline consistently shade your panels at certain times of day, your solar forecast provider has no way to know — it models weather and panel geometry, not your specific obstruction, so it over-forecasts the same hours every day regardless of cloud cover. Shade correction learns a per-hour correction by comparing your forecast against your own actual production history (via Home Assistant's own recorder — no data leaves your instance for this), and feeds it into the battery optimiser's forecast, not just a display number.
Off by default. Turn it on under Settings → Devices & Services → Grid Lens → Configure → Shade correction — it needs a Solar production sensor configured (see Required sensors above) to learn from. The forecast sensor it compares against is auto-detected; you only need to pick one manually if you run more than one forecast source.
A deferrable load is electricity usage you can shift to a cheaper time of day — for example an EV charger, pool pump, hot water system, or air conditioner.
To include a deferrable load in the optimisation, you need a sensor that measures its consumption. Grid Lens will model what each plan would cost if you shifted that load to its cheapest window.
Configure deferrable loads under Settings → Devices & Services → Grid Lens → Configure → Deferrable loads after setup. You set up one appliance at a time, and Grid Lens only asks what that appliance actually needs — a pool pump it can’t switch takes three answers, while a modulating EV charger is walked through its setpoint and battery settings on their own screens.
No consumption sensor at all for a controllable appliance (common for an IR-remote-controlled aircon)? Grid Lens can estimate one for you — see Estimated loads under Load control below.
Each deferrable load has a weekly schedule — a per-weekday, half-hourly grid of when that appliance is allowed to run. Grid Lens picks the cheapest half-hours inside your rules; it never runs a load outside them.
Edit it on the Allowed Run Times card on the Grid Lens dashboard by painting hours with the mouse. A pool pump might be daytime-only; an EV charger might be unrestricted.
Grid Lens learns how much energy each deferrable load needs per day from its own sensor, averaged over the last 14 days. When today isn't typical — a long drive tomorrow, guests staying — override it with Today Boost, on the Power Flow page's expandable device panel or on the Deferrable Loads card (same controls, either place).
Set the kWh you actually need today; 0 means "use the historical average". The plan re-solves around it immediately.
A chart next to the input shows each device's actual daily use over the last two weeks, with the average of those days beside it — so you can see what "typical" is before deciding how far above it to go. Devices are listed biggest-consumer-first, so the ones most worth adjusting are at the top.
If you ask for more than the load's allowed window can physically deliver, the card shows you that ceiling rather than silently ignoring the excess.
If a load has its own battery with a charge ceiling set (an EV charged only to, say, 90%), and today it starts already close to that ceiling, Grid Lens can only schedule the charge that fits underneath it — which may be well below the 14-day average. When that happens the row shows a “SOC-limited” line with what it scheduled versus the usual amount; raise the load's Max SOC % under Configure to allow more.
Today Boost tells Grid Lens how much energy a load needs today — but not by when. If you're heading off on a long drive and want the car at 100% by a specific time, set a charge target instead: a percentage and a deadline, on any load with an SOC sensor and capacity configured (the same setup Today Boost's SOC-limited ceiling uses).
Grid Lens still picks the cheapest, most solar-heavy slots between now and your deadline — it only forces full-power charging in the run-up if that's what it takes to make the target in time. It's not the same as forcing the load On, which charges flat-out immediately regardless of price.
Find it on the Grid Lens dashboard under Settings → Charge Targets — one row per eligible load, with a percentage field and a date/time field. Set both to activate; leaving the percentage at 0 cancels it. It's also available as two Home Assistant services, grid_lens.set_charge_target and grid_lens.clear_charge_target, for scripts and automations.
The target clears itself automatically once the load reaches it, or once the deadline passes — nothing to remember to turn back off.
Comparison and planning are read-only. Battery control is the optional step where Grid Lens actually operates your inverter to follow the plan it found.
Turn on the Battery Control switch. From then on, every five minutes Grid Lens reconciles your battery against the current plan — charging from solar, charging from the grid during genuinely free or cheap windows, holding, or discharging into expensive periods.
Battery control is brand-agnostic by design. Sigenergy is supported today; more inverter drivers are being added.
Grid Lens can also switch simple on/off appliances — anything exposed to Home Assistant as a switch entity that draws roughly a fixed power when running (a pool pump, a smart-plug-fed charger, a resistive heater) — or as a climate entity, so an air conditioner works the same way. Grid Lens only ever decides when it runs, never its mode or target temperature — those stay under your own control.
An EV charger that accepts a charging-current limit is handled differently, and better — see EV chargers below.
Assign a control switch (or climate entity) to a deferrable load via Grid Lens → Configure. Each controllable load then gets its own controls — on the Power Flow page's expandable device panel and on the Deferrable Loads card:
| Control | Default | What it does |
|---|---|---|
| Control switch | Off | Master opt-in — Grid Lens drives this appliance per the plan. |
| On now / Off now | — | Manual override. Forces the appliance and stops Grid Lens driving it entirely, until you choose Auto. |
| Auto | — | Hands control back to the plan. |
An EV charger is not really an on/off appliance. Most can be told how many amps to deliver, and Grid Lens will use that: instead of slamming the charger fully on or fully off, it dials the charging current up and down to match what the plan wants and what your solar is actually producing right now.
This works with any charger integration that exposes a charging-current limit as a Home Assistant number entity — which is essentially all of them. Known-good shapes include OCPP (number.…_maximum_current), Easee, Wallbox, Zaptec, go-e, openEVSE, Tesla and Sigenergy. Point Grid Lens at that entity under Grid Lens → Configure and it takes over from there; there's no per-brand setup required.
Setting up a charger from a list, when yours is on it. The Deferrable Loads wizard's first modulating-load screen offers an optional Charger Brand dropdown. Pick your charger's brand and Grid Lens scans this Home Assistant instance for that brand's entities and pre-fills the fields below — still fully editable, nothing is saved until you finish the wizard as normal. Leave it on "Other" (the default) to fill everything in by hand, exactly as before this existed. A brand marked "(unverified pattern)" in the list hasn't been confirmed against real hardware yet — worth trying, but check what it fills in before saving; not listed at all just means pick the entities yourself below, same as always.
Some brands also carry a short Charger brand note, shown on the next screen once you've picked that brand. It only appears when there is something about that charger worth knowing before you save — typically a setting in the charger's own integration that would otherwise quietly fight Grid Lens's schedule. For a go-eCharger / Wattpilot, for instance, the note points you at a switch.…_charge_pause entity that ships disabled: if you enable it and leave it on, the charger inserts its own pauses that Grid Lens knows nothing about, so the note tells you to leave it off.
| Setting | Default | What it does |
|---|---|---|
| Charging current entity | — | The charger's current-limit number entity. Leave it empty to keep plain on/off control. |
| Units / phases / voltage | Auto | Detected from the entity itself. Only set these if auto-detection gets it wrong. |
| Minimum current | 6 A | The lowest current your car will accept. Rarely needs changing. |
| Plugged-in sensor | — | Optional. Lets Grid Lens stop commanding a charger with no car attached. |
| Start / Stop buttons | — | Optional pair, for a charger with no stateful on/off switch at all, or whose current entity refuses to be set to exactly 0. Leave both blank if your Control Entity switch (or writing 0 A) already stops delivery — that's the common case. If used, both must be set together. |
| Max Current | Charger maximum | Your own ceiling — "never charge above 10 A", whatever the plan wants. |
With Greedy Consumption switched on, a modulating charger does something an on/off one can't: it tracks your surplus continuously, every 30 seconds, ramping the current to absorb exactly what you're exporting. An on/off appliance has to wait until the whole of its draw is covered before it can switch on at all. For live surplus tracking you'll also need a grid power sensor configured — without one, the charger simply follows the optimiser's plan instead.
Some controllable appliances have no way to report their energy use at all — the classic case is an air conditioner driven by an infrared blaster, which can only send commands, never read anything back. You can still add these under Grid Lens → Configure → Deferrable loads → Add a deferrable load, choosing “No energy sensor, but I can switch it on and off from HA”: give it a name, its control entity, and a rough estimate of its power draw in kW.
Turn on auto-refine and point Grid Lens at a whole-house load power sensor, and it will quietly improve that estimate over time: whenever the appliance switches on, it compares your house's power draw just before and a few minutes after (long enough for a compressor to spin up) and folds a plausible reading into a running estimate. It learns from ordinary use — you don't need to do anything for it to collect data — and discards anything that looks unreliable (another controlled device changing state at the same time, an implausible jump). Leave auto-refine off, or skip the load power sensor, and it simply stays on your manual estimate.
Once configured, an estimated load behaves exactly like any other deferrable load — it gets its own schedule, Today Boost, Greedy Consumption, and all the same controls above.
On most solar homes there are hours every day when your battery is full, your panels are still producing, and the surplus goes to the grid for a feed-in tariff of almost nothing. That's free energy leaving the house.
Greedy Consumption lets a load opportunistically run whenever energy is genuinely free, regardless of what the plan scheduled for that moment. Enable it per appliance. There are three triggers:
| Trigger | Fires when | Can it cost money? |
|---|---|---|
| Free import | Your plan's import price for this window is zero. | No |
| Export surplus | Your feed-in price is at or below your Minimum Export Price (zero if you haven't set one) and you're already exporting at least as much as this appliance draws — so running it can't create new grid import, it just uses export you'd rather not sell that cheap. | No new import — only gives up feed-in revenue below the floor you set |
| Forecast surplus | Over the next several hours — up to the point your plan itself next draws the battery down for something it values, like an evening export peak — the plan expects to export energy below your Minimum Export Price (zero if you haven't set one) at a rate that's worth running the appliance for. It runs proportionally to that rate (a fraction of full power for a charger, fully on for a simple switch) rather than all-or-nothing, and only once your battery has both the discharge rate and the spare charge to actually supply it, so it draws down the battery rather than the grid. | No new import — only forgoes below-floor export the plan would have made anyway |
The first two only fire once free energy is already flowing. That's often too late: mid-morning your battery absorbs every spare watt, so nothing looks free, even though the plan already knows the afternoon will spill far more than the appliance could ever consume. By the time surplus export actually appears, hours of run-time are gone.
Forecast surplus fixes that by starting the load early — proportionally, at the average rate the plan expects to waste energy over the safe part of that window. It's a separate opt-in because it's the one trigger that fires ahead of any live signal — the other two only ever confirm energy that is already flowing. It's safe two ways: it stops looking ahead at the point your plan itself starts drawing the battery down for something valuable (so it never borrows charge your plan was saving for the evening), and it checks, live, that your battery has both the discharge rate and enough spare charge to supply the appliance for the whole of that window right now — running it then draws the battery down instead of the grid, and that gap gets refilled by the very energy the forecast expects to spill. No battery configured (or its sensors not readable) simply means this trigger never fires — there's no buffer to safely bet on.
The export surplus trigger needs a live signed grid power sensor — positive when importing, negative when exporting — configured as grid_power_sensor under Grid Lens → Configure. Without it that one trigger simply never fires; the other two still work.
By default the two live triggers only count export as wasted when the feed-in price is zero. Set a Minimum Export Price (on the dashboard, in cents/kWh) to raise that bar — e.g. at 5c, a load set to run greedily will soak up surplus any time you'd otherwise be exporting below 5c. The same figure also drives Forecast surplus: if the plan shows a whole afternoon of, say, 3c export, a greedy load with Forecast surplus enabled will start now, off the battery, rather than wait for that spill. Leave it at 0 to keep the strict "only when feed-in is zero" behaviour on all three triggers.
The forecast surplus trigger needs your battery SOC sensor, a live signed battery charge/discharge power sensor — positive when charging, negative when discharging — and your battery capacity (kWh), the same battery details Grid Lens already uses to plan your battery. The capacity figure backs the check that your battery can absorb the trigger's full draw before it starts refilling, not just supply it for an instant. Without all three configured and readable, this trigger simply never fires; the other two still work.
If you have already set up the Power Flow card, you have told Grid Lens this entity once and it is filled in for you — the card's grid_power_entity is the same reading with the same sign convention, so the setup form offers it back rather than asking twice. Otherwise the field starts blank: the other energy sensors come from your Home Assistant Energy dashboard, but that dashboard only records cumulative energy and has no live power reading to borrow.
If it is blank and Greedy Consumption is on, the Power Flow page's device panel (or the Deferrable Loads card) says so — the appliance's greedy line reads “export is being wasted, but no grid power sensor is set” rather than pretending it is still waiting for surplus.
Note this is a power (W) sensor, not one of the cumulative kWh sensors from your Energy dashboard.
Grid Lens keeps a running Greedy Consumption energy sensor per appliance, tracked from the moment you enable it (there's no way to know retroactively what ran opportunistically before that). It's what powers the Plan Comparison page's Exclude Greedy Consumption checkbox — see View the dashboard.
Anything that acts on your house should be able to explain itself. Every automated decision Grid Lens makes is visible on the dashboard:
The free plan requires no API key — Grid Lens registers your installation automatically and grants access to model your current plan.
A Pro subscription ($1/month) gives you an API key that unlocks all available plans. Enter it under Grid Lens → Configure → API key & connection.
If you remove and re-add the integration, setup will tell you the installation is already registered and ask for your existing key. We only store a hashed copy, so we can't show it to you again — keep it somewhere safe, or email support@gridlens.au from your registered address for a replacement.
Ensure you fully restarted Home Assistant (not just reloaded). Custom integrations require a full restart to register.
Make sure your energy sensors appear in the Energy dashboard first. Grid Lens reads from the same sensor list.
Grid Lens needs at least 24 hours of sensor history to run the LP optimiser. If you've just set it up, check back the following day.
Add to your configuration.yaml:
logger:
logs:
custom_components.grid_lens: debug
Then check Settings → System → Logs for grid_lens entries.
Still stuck? Email support@gridlens.au.