Simulating a Solar Panel & Battery in Home Assistant Before Buying One

Table of Contents
I’ve been thinking about installing a balcony solar panel and battery storage system at home. Before spending the money, I wanted to answer a simple question: given my actual house’s light levels and electricity consumption, would it be worth it?
Rather than guessing, I built a simulation directly in Home Assistant using sensors I already had. It started as a pile of template sensors, helpers and a 5-minute automation. Eventually I packaged the whole thing into a custom integration: ha-virtual-solar. Install it from HACS, point it at two sensors, and you get a live dashboard estimating solar output and a virtual battery charging and discharging in real time.
Why I Built It #
Balcony solar in Germany has become genuinely attractive in the last couple of years. The legal cap on plug-in inverter output has risen to 800 W, panels keep getting cheaper, and a complete kit with a small battery now lands somewhere in the €700-€1,500 range. That’s no longer a small spend for “let’s see what happens”, but it’s not enough that anyone is going to hand-design a system around your specific apartment. s The vendor calculators all give you average numbers for “Berlin” or “Munich”. Useful, but my balcony faces a specific direction, has a specific amount of obscuration from the building opposite, and my household’s evening cooking and washing consumption pattern looks nothing like the textbook curve. The difference between “this pays back in 4 years” and “this never pays back” can hinge on whether the battery fills up on an average Tuesday in March.
The thing I already had in Home Assistant: a Zigbee lux sensor mounted outdoors on a windowsill, and a smart meter reporting instantaneous household power draw. That’s exactly the two inputs you need to roughly estimate what a panel + battery would do at my house, every minute, all year round, with real data.
The hack version was straightforward: a template sensor turning lux into estimated W, an input_number helper acting as a virtual battery level, and a 5 minute automation nudging the helper up or down by (solar − house consumption). It worked. But it kept growing. Battery percentage, charge rate, time to full, panel configuration helpers, status logic, a dashboard. By the time I’d added the seventh template sensor, it was easier to package the whole thing as a proper integration than to maintain a sprawl of YAML.
That’s ha-virtual-solar. The rest of this post is how to set it up and what it does.
The Hardware I’m Considering #
- Solar panels: configurable from 1 to 20 panels, 100 to 800 W each. The Anker supports up to 4 panels across its MPPT inputs (3,600 W total), but the integration ships profiles for other kits too.
- Battery: Anker SOLIX Solarbank 3 E2700 Pro (2.68 kWh capacity, 1200 W max charge/discharge rate). The integration also has profiles for the EcoFlow DELTA 2, generic 800 W balcony kits, and 5 kW residential rooftops.
The goal isn’t pinpoint accuracy. It just needs to be realistic enough to answer: on a typical day, would the battery fill up? Would it cover my evening consumption?
Sensors Used #
| Sensor | What it provides |
|---|---|
sensor.sensor_light_illuminance | Ambient light in lux (Zigbee sensor via Zigbee2MQTT) |
sensor.esphome_glow_power_consumption | Real-time household power draw in Watts (Hildebrand Glow smart meter IHD via ESPHome) |
Any pair of sensors with device_class: illuminance and device_class: power will work. Sensor placement matters more than anything else: an indoor lux sensor will dramatically understate output. The Zigbee sensor I’m using is mounted outdoors, unobstructed, at roughly the same angle the panel would be.
The Theory: Lux to Watts #
Sunlight has a well-known relationship between illuminance (lux) and irradiance (W/m²):
1 W/m² ≈ 120 lux for sunlight
Solar panels are rated at Standard Test Conditions (STC) of 1000 W/m². The general formula for any number of panels:
estimated_watts = (lux / 120) × ((panel_wattage × panel_count) / 1000) × system_efficiency
system_efficiency is a single multiplier that wraps inverter losses, wiring losses, and thermal derating into one value (defaults to 95 %).
Some example values to calibrate expectations (1× 500 W panel at 95 % efficiency):
| Condition | Lux | Estimated Output |
|---|---|---|
| Overcast | 1,000 lx | ~4 W |
| Partly cloudy | 20,000 lx | ~79 W |
| Bright sun | 80,000 lx | ~317 W |
| Full sun | 100,000 lx | ~396 W |
Caveat: Accuracy depends heavily on sensor placement. Ideally the light sensor should be outdoors, unobstructed, and angled the same way as the panel. Expect ±20 % in practice.
Installing the Integration #
ha-virtual-solar is distributed via HACS as a custom repository. You need HACS already installed; if you don’t have it yet, the HACS install guide takes about five minutes.
- Open HACS in the Home Assistant sidebar.
- Integrations → 3-dot menu (top right) → Custom repositories.
- Paste
https://github.com/virtuallytd/ha-virtual-solar, choose category Integration, click Add. - The integration now appears in the HACS list. Click it, then Download.
- Restart Home Assistant (Settings → System → Restart).
- Once back up: Settings → Devices & Services → Add Integration, search for “Virtual Solar”.
That gets you to the setup wizard.
The Setup Wizard #
Four steps. Picking a profile in step 1 prefills the defaults in steps 3 and 4, so the more obscure your kit, the more important the profile picker is.
Step 1: Profile
A dropdown of preset kits:
- Anker SOLIX SOLARBANK 3 E2700 Pro
- EcoFlow DELTA 2
- Generic 800 W balcony solar (DE)
- Generic 5 kW residential rooftop
- Custom (no preset)
If your kit isn’t there, pick Custom and you fill everything in manually. If it’s close to one of the presets, pick that and tweak the values in later steps. (Profiles live in a YAML file inside the integration. Adding one is a few-line PR.)

Step 2: Sensors
Two dropdowns:
- Ambient light sensor (lux): filtered to
device_class: illuminance. Pick your outdoor lux sensor. - Whole-house power consumption sensor: filtered to
device_class: power. Pick whatever reports your household instantaneous draw in watts.
If the dropdown is empty, the integration can’t find a sensor with the right device class. Check that your sensor’s device_class is set correctly in Developer Tools → States.

Step 3: Solar panels
Initial values for the panel sliders. These get prefilled from the profile. You can change them live from the dashboard after setup, so don’t agonise.
- Rated wattage of one panel: 100 to 800 W, step 10.
- Number of panels: 1 to 20.
Step 4: Virtual battery
Storage and inverter specs:
- Battery capacity (kWh): total storage. Also editable live via the dashboard.
- Max charge rate (W): how fast the battery can absorb energy.
- Max discharge rate (W): how fast it can supply energy. Often equal to charge rate; sometimes higher (the EcoFlow DELTA 2 is 500 W in / 1800 W out).
- System efficiency (%): the multiplier on solar output. 95 % is fine for most systems.
Click Submit. The integration creates a “Virtual Solar” device with eight entities under it, and you’re done. No input_number helpers to create, no automations to write.

What You Get #
The integration creates a single device with these entities:
| Entity | What it does |
|---|---|
sensor.virtual_solar_estimated_output | Solar output in W, derived from lux × panel config × efficiency. |
sensor.virtual_solar_battery_percentage | Charge level as %, with a dynamic icon. |
sensor.virtual_solar_battery_charge_rate | Net W into (positive) or out of (negative) the battery, clamped at the configured max rates. |
sensor.virtual_solar_battery_time_to_full | Human-readable countdown like 2h 15m, or Full / No solar input. |
sensor.virtual_solar_battery_status | Charging / Discharging / Full / Empty. Action wins over condition: a 0 % battery being charged shows Charging, not Empty. |
number.virtual_solar_battery_level | Current stored energy in kWh. Ticks every minute. Editable so you can manually reset to 0 or full. |
number.virtual_solar_battery_capacity | Total capacity in kWh. Live-editable; the level slider auto-resizes. |
number.virtual_solar_panel_count / panel_wattage | Live sliders so you can experiment with array sizing from the dashboard. |
number.virtual_solar_system_efficiency | Inverter + wiring + thermal losses combined, as a percentage. |
The Dashboard #
The integration ships a service that builds a Lovelace dashboard YAML using your specific entity IDs. No find-and-replace needed.
- Developer Tools → Actions.
- Select Virtual Solar: Get dashboard YAML, click Perform action.
- Copy the entire response (starts with
views:). - Settings → Dashboards → Add Dashboard → New dashboard from scratch.
- Open the new dashboard → 3-dot menu → Raw configuration editor, select all, paste, save.
The generated dashboard includes:

- Two gauges at the top: estimated solar output (with severity colours) and battery percentage.
- Battery status indicator: a single-line entity card showing
Charging/Discharging/Full/Emptywith a matching icon. - Current Status card: solar output, house consumption, net battery flow, light level.
- Battery card: charge level, energy stored, time to full, capacity.
- Simulation card: panel wattage / count / system efficiency sliders for live experimentation.
- History graphs: 24h solar output, 24h battery level, 7-day solar + net flow overlay.



Playing With “What If” #
The panel count, panel wattage, battery capacity, and system efficiency are all live sliders on the dashboard. Drag any of them and every downstream sensor recalculates within a few seconds. The battery level slider is also user-editable, so you can manually reset it (e.g. to 0 to simulate starting from depleted, or to capacity to test the “Full” state).
Some experiments worth running:
- Pull the panel count from 1 up to 3 and watch the battery fill faster.
- Drop the system efficiency from 95 % to 80 % and see how much real-world output you lose to a bad inverter or shading.
- Bump capacity from 2.68 kWh to 5 or 10 and watch the 7-day graph: does the larger battery actually carry your house through the evenings, or does it never get fully charged?
What to Look For #
After running this for a few weeks, the data should tell you:
- Does the battery fill up during the day? If it consistently hits 100 % by midday, a larger capacity (or another panel) could be worthwhile.
- Does it drain overnight? Track how much the battery discharges during evening/night hours. That’s the real-world value you’d get from the storage.
- Seasonal difference: Run it through summer and winter. Lux readings drop dramatically in winter, which directly impacts output.
- Peak shaving: Watch the “Net Battery Flow” sensor. When it’s deeply negative (house consuming far more than panels produce), that’s grid energy you’d be drawing without the battery.
Limitations #
The integration handles a lot of the modelling automatically: charge and discharge rate clamping, capacity bounds, state restoration across restarts. There are still things it doesn’t model:
- The
1 W/m² ≈ 120 luxconstant is an approximation that varies with sun angle and cloud type. - The light sensor needs to be outdoors and unobstructed for meaningful readings.
- Panel temperature derating and panel degradation aren’t modelled separately. The single
system_efficiencyvalue is a rough catch-all. - Battery roundtrip efficiency and self-discharge aren’t modelled. Charge in = charge stored.
- The simulation assumes the battery is the sole source of storage and doesn’t model export to the grid.
Despite these caveats, it’s a genuinely useful tool for understanding your home’s energy profile before committing to a purchase. The source is on GitHub at virtuallytd/ha-virtual-solar. Issues and profile contributions welcome.