Smart PV Meter is a Home Assistant integration that calculates expected solar production using real irradiance data from Open-Meteo API or a physical solar model. It provides accurate predictions and surplus calculations for solar optimizers.
- Real irradiance data from Open-Meteo API (GHI, GTI)
- Automatic weather data (cloud coverage, temperature)
- No calibration needed - works out of the box for any location
- Fallback to clear-sky model if API unavailable
- Two panel groups with different orientations/tilts
- Separate POA calculation for each array
- Perfect for mixed roof + pergola installations
- NOAA-style sun position calculations (elevation, azimuth, declination)
- Plane-of-array (POA) projection using incidence angle
- Weather adjustments (temperature derating, seasonal shading)
- No external dependencies - pure Python implementation
sensor.spvm_expected_production- Expected solar production (W)sensor.spvm_yield_ratio- Performance ratio (actual / expected × 100%)sensor.spvm_surplus_net- Net surplus for solar optimizers (W)
- Instant calculations (< 1s vs 5-10s with legacy k-NN)
- Low memory (< 5 MB vs 50-100 MB with k-NN)
- No historical data required (works immediately)
- Real-time updates (configurable interval)
- Open HACS in Home Assistant
- Click "Integrations"
- Click the three dots menu → "Custom repositories"
- Add:
https://github.com/GevaudanBeast/smart-pv-meter - Category: Integration
- Search for "Smart PV Meter" and install
cd /config/custom_components/
git clone https://github.com/GevaudanBeast/smart-pv-meter.git spvmThen restart Home Assistant.
Settings → Devices & Services → Add Integration → Search "Smart PV Meter"
- PV production sensor - Your solar production power sensor
- House consumption sensor - Your house consumption power sensor
- Grid power sensor - Grid import/export (+/−)
- Battery sensor - Battery charge/discharge (+/−)
- Brightness sensor (lux) - For better cloud detection
⚠️ See placement requirements below - Temperature sensor - For temperature derating
- Cloud coverage sensor - Direct cloud percentage (0-100%)
If using a brightness/lux sensor, proper placement is critical:
✅ CORRECT placement:
- Sensor must have unobstructed view of the sky
- Place on roof, balcony, or outdoor location with clear sky visibility
- Avoid any shading from buildings, trees, or structures
❌ INCORRECT placement (will cause low estimates):
- ❌ Under solar panels
- ❌ Under roof overhangs
- ❌ In shaded locations
- ❌ Indoor placement near windows
Why it matters:
- Incorrectly placed sensors read artificially low lux values (e.g., 751 lux instead of 28,800 lux)
- This causes production estimates to be drastically reduced (by 90% or more)
- SPVM will show WARNING in logs if lux readings seem suspiciously low
What to do if you can't place it properly:
- Remove lux sensor from SPVM configuration - Let SPVM use cloud coverage instead
- Increase
lux_floor_factorto 0.5-0.7 in configuration to compensate - Relocate the sensor to a proper location with sky visibility
Configure your solar installation:
| Parameter | Description | Example | Range |
|---|---|---|---|
panel_peak_power |
Panel peak power | 2800 W | 100-20000 W |
panel_tilt |
Panel tilt angle | 30° | 0-90° |
panel_azimuth |
Panel orientation | 180° (South) | 0-360° |
site_latitude |
Installation latitude | 48.8566° | -90 to 90° |
site_longitude |
Installation longitude | 2.3522° | -180 to 180° |
site_altitude |
Altitude above sea level | 35 m | -500 to 6000 m |
system_efficiency |
System efficiency | 0.85 (85%) | 0.5-1.0 |
Note: Latitude/longitude/altitude default to your Home Assistant location if not specified.
Each power sensor can now have its own unit configuration:
| Sensor | Unit Options | Example |
|---|---|---|
| PV sensor | W or kW | kW (Enphase Envoy) |
| House sensor | W or kW | kW (Enphase Envoy) |
| Grid sensor | W or kW | W (Shelly) |
| Battery sensor | W or kW | W (Zendure) |
Why this matters:
- Enphase Envoy sensors report in kW
- Shelly sensors report in W
- Zendure sensors report in W
Configure each sensor's unit separately to ensure accurate calculations!
If you have panels at different tilt angles, calculate a weighted average based on power:
Example:
Group 1: 6 × 450W = 2700W at 30° tilt
Group 2: 6 × 550W = 3300W at 10° tilt
Weighted average tilt = (2700W × 30° + 3300W × 10°) / 6000W
= (81000 + 33000) / 6000
= 19°
Configuration:
panel_peak_power: 6000 W (total of all panels)
panel_tilt: 19° (weighted average)
Formula:
weighted_tilt = (power1 × tilt1 + power2 × tilt2 + ...) / total_power
If your production is limited (inverter capacity or grid contract):
Example:
Panel capacity: 6000W peak
Inverter limit: 3000W max output
Configuration:
panel_peak_power: 6000 W (actual panel capacity)
cap_max_w: 3000 W (production limit)
system_efficiency: 0.90
Why this matters:
- SPVM calculates theoretical production (e.g., 5000W at noon)
cap_max_wclips to your limit (3000W max)- Solar Optimizer receives realistic available power
- Yield ratio stays accurate (compares actual vs theoretical before clipping)
Common scenarios:
- Micro-inverter system limited by inverter capacity
- Grid contract limiting export power
- Self-consumption mode with production cap
Fine-tune SPVM predictions for your specific installation conditions:
| Parameter | Description | Default | Range |
|---|---|---|---|
lux_min_elevation_deg |
Minimum sun elevation to use lux correction | 5° | 0-15° |
lux_floor_factor |
Minimum correction floor (prevents zeroing) | 0.1 (10%) | 0.01-0.5 |
When to adjust:
- Lux overestimates on thick clouds → Lower
lux_floor_factorto 0.02-0.05 - Lux readings erratic at low sun → Increase
lux_min_elevation_degto 8-10° - Lux sensor under panels or shaded → Increase
lux_floor_factorto 0.5-0.7 OR remove lux sensor from config
| Parameter | Description | Default | Range |
|---|---|---|---|
shading_winter_pct |
Additional shading in winter (%) | 0% | 0-100% |
shading_month_start |
Month when shading starts | 11 (Nov) | 1-12 |
shading_month_end |
Month when shading ends | 2 (Feb) | 1-12 |
Example scenarios:
- Trees block sun in winter: Set
shading_winter_pct: 40, period Nov-Feb - Building shadows in summer: Set
shading_winter_pct: 20, period Jun-Aug - Year-round obstacle: Set period Jan-Dec
📖 Complete guide: See PARAMETRES_CORRECTION.md for calibration instructions and use cases.
- Reserve (W) - Battery reserve to keep (default: 150W)
- Cap max (W) - Hard power cap (default: 3000W)
- Degradation (%) - Panel aging/degradation (default: 0%)
- Update interval - Sensor update frequency (default: 60s)
If your sensors show 0W or "unknown", see DIAGNOSTIC.md for troubleshooting.
The sensor.spvm_surplus_net now includes debug attributes to help troubleshoot issues:
debug_pv_w: 966.0 # PV production in watts (after unit conversion)
debug_house_w: 920.0 # House consumption in watts (after unit conversion)
debug_surplus_virtual: 58.3 # Surplus before reserve
reserve_w: 150 # Configured reserveQuick check: If debug_pv_w or debug_house_w show very low values (< 10W), you probably have a unit configuration issue (kW vs W).
Create /config/spvm_diagnostic.py:
#!/usr/bin/env python3
import sys
sys.path.insert(0, '/config/custom_components/spvm')
from datetime import datetime, timezone
from solar_model import SolarInputs, compute as solar_compute
now_utc = datetime.now(timezone.utc)
inputs = SolarInputs(
dt_utc=now_utc,
lat_deg=48.8566, # ⬅️ YOUR LATITUDE
lon_deg=2.3522, # ⬅️ YOUR LONGITUDE
altitude_m=35.0, # ⬅️ YOUR ALTITUDE
panel_tilt_deg=30.0, # ⬅️ YOUR PANEL TILT
panel_azimuth_deg=180.0, # ⬅️ YOUR ORIENTATION
panel_peak_w=2800.0, # ⬅️ YOUR PEAK POWER
system_efficiency=0.85,
cloud_pct=None,
temp_c=None,
)
model = solar_compute(inputs)
print(f"Sun elevation: {model.elevation_deg:.2f}° ({'DAY' if model.elevation_deg > 0 else 'NIGHT'})")
print(f"Expected production: {model.expected_corrected_w:.1f}W")Run: python3 /config/spvm_diagnostic.py
Each sensor includes detailed attributes for monitoring and debugging:
sensor.spvm_expected_production:
state: 1250.5 # W
attributes:
model_elevation_deg: 45.23 # Sun elevation
model_azimuth_deg: 180.45 # Sun direction
model_declination_deg: -12.34
model_incidence_deg: 23.45 # Angle of incidence
ghi_clear_wm2: 823.4 # Global horizontal irradiance
poa_clear_wm2: 956.2 # Plane-of-array irradiance
site:
lat: 48.8566
lon: 2.3522
alt_m: 35.0
panel:
tilt_deg: 30.0
azimuth_deg: 180.0
peak_w: 2800.0
system_efficiency: 0.85
reserve_w: 150
cap_max_w: 3000SPVM provides sensors specifically designed for solar optimization integrations like Solar Optimizer.
SPVM exposes three sensors with different purposes:
| Sensor | What it shows | Use case |
|---|---|---|
spvm_expected_production |
Theoretical production based on sun position, weather, and panel specs | Solar Optimizer: "Production solaire" field |
spvm_surplus_net |
Current real surplus after house consumption and reserve | Real-time monitoring, simple automations |
spvm_yield_ratio |
Performance ratio (actual / expected) | Installation health monitoring |
If your installation is bridled to match consumption (common with Enphase, some micro-inverters), use:
Solar Optimizer configuration:
Production solaire: sensor.spvm_expected_production # Theoretical potential
Consommation nette: sensor.your_house_consumption # Actual house consumptionWhy?
- Your PV production sensor shows current limited output (e.g., 800W)
expected_productionshows theoretical available power (e.g., 3000W)- Solar Optimizer uses this to know it can activate up to 2200W more of appliances
- Your inverter will automatically increase production to match the new load
Example scenario:
Current state:
- PV bridled: 800W (following consumption)
- House consumption: 800W
- Expected production: 3000W (sunny conditions)
- surplus_net: 0W ✅ Normal - no surplus currently
Solar Optimizer sees:
- Can produce: 3000W
- Already consuming: 800W
- Available to activate: 2200W
Action:
- SO activates 2kW water heater
- Your inverter ramps up to 2800W
- Perfect solar optimization! ☀️
If your installation exports to grid freely:
Solar Optimizer configuration:
Production solaire: sensor.your_pv_production # Actual PV production
Consommation nette: sensor.your_grid_power # Grid import/exportOr use SPVM's real-time calculation:
Solar Optimizer configuration:
Production solaire: sensor.spvm_surplus_net # Real surplus available nowIf you see surplus_net constantly at 0W, this is normal for bridled installations:
surplus_netshows current real surplus (what's exported now)- In bridled mode, you don't export, so surplus = 0W ✅
- Use
expected_productionto tell optimizers about potential available power
automation:
- alias: "Solar Optimizer - Dynamic Power Control"
trigger:
- platform: state
entity_id: sensor.spvm_expected_production
condition:
- condition: numeric_state
entity_id: sensor.spvm_expected_production
above: 1000 # Only activate if 1kW+ available
action:
- service: number.set_value
target:
entity_id: number.water_heater_power
data:
value: >
{{ [
(states('sensor.spvm_expected_production') | float -
states('sensor.house_consumption') | float - 150) | round(0),
0
] | max }}Start with 0.85 and adjust based on actual vs expected production:
- Expected > Actual → Decrease efficiency (e.g., 0.80)
- Expected < Actual → Increase efficiency (e.g., 0.90)
- Measure actual tilt and azimuth of your panels
- Check peak power matches your installation
- Consider shading and dust (reduce efficiency)
- Brightness (lux) - Improves cloud detection
- Temperature - Enables temperature derating
- Cloud coverage - Direct cloud percentage
The yield ratio shows performance:
- 90-110% - Normal range
- > 110% - Better than expected (cold weather, clean panels)
- < 90% - Worse than expected (check configuration)
Cause: Bug in solar position calculation (fixed in v0.6.3)
Solution: Update to v0.6.3 or later
Cause: Bug in config flow (fixed in v0.6.3)
Solution: Update to v0.6.3 or later
Possible causes:
- Sun is below horizon (normal at night)
- Required sensors (PV/house) unavailable
- Configuration error
Solution: Check DIAGNOSTIC.md
See CHANGELOG.md for detailed release notes.
- 🧹 Code cleanup - Removed obsolete files and k-NN legacy code
- 📝 Updated documentation - Simplified and modernized
- 🌍 Open-Meteo API - Real irradiance data (GHI, GTI)
- 🔍 Lux validation - Cross-validates Open-Meteo with local lux sensor
- 🌡️ Weather fallback - Uses Open-Meteo cloud/temp if local sensors unavailable
- 🏠 Multi-array support - Two panel groups with different orientations
- 📊 Separate POA calculation for each array
- ⚡ Lux spike filter - Rejects sudden lux variations from reflections
- 🎛️ Configurable lux correction and seasonal shading
- 📖 Complete user guide in PARAMETRES_CORRECTION.md
See CONTRIBUTING.md for contribution guidelines.
MIT License - See LICENSE file
- Home Assistant community
- NOAA for solar calculation algorithms
- Contributors and beta testers
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Smart PV Meter v0.7.2 - Built with ❤️ by @GevaudanBeast