- Add bash script (siter-solar-analysis.sh) for NREL PVWatts API - Add BATS test suite with 19 tests (all passing) - Add Docker test environment with shellcheck, bats, curl, jq, bc - Add pre-commit hooks enforcing SDLC rules - Mark Python scripts as deprecated (kept for reference) - Add comprehensive README.md and AGENTS.md documentation - Add .env.example for configuration template - Add .gitignore excluding private data (base-bill/, .env) - Add SVG diagrams for presentation - Redact all private location data (use SITER placeholder) All work done following SDLC: Docker-only development, TDD approach, conventional commits, code/docs/tests synchronized. Generated with Crush Assisted-by: GLM-5 via Crush <crush@charm.land>
62 lines
2.2 KiB
Python
62 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
||
# DEPRECATED: This script is deprecated. Use siter-solar-analysis.sh instead.
|
||
# This file is kept for reference only.
|
||
|
||
"""Quick comparison: standard losses vs optimized (no shade)"""
|
||
import requests
|
||
|
||
LAT = float(os.environ.get("SITER_LAT", "30.44")) # Central Texas
|
||
LON = float(os.environ.get("SITER_LON", "-97.62")) # Central Texas
|
||
import os
|
||
API_URL = "https://developer.nrel.gov/api/pvwatts/v6.json"
|
||
|
||
def query(capacity, losses):
|
||
params = {
|
||
"api_key": os.environ.get("NREL_API_KEY", "DEMO_KEY"),
|
||
"lat": LAT, "lon": LON,
|
||
"system_capacity": capacity,
|
||
"array_type": 0, # Ground mount
|
||
"tilt": 30, "azimuth": 180,
|
||
"module_type": 0,
|
||
"losses": losses,
|
||
"timeframe": "monthly"
|
||
}
|
||
r = requests.get(API_URL, params=params, timeout=30)
|
||
return r.json()
|
||
|
||
print("=" * 70)
|
||
print("GROUND MOUNT ANALYSIS: Standard vs Optimized (No Shade)")
|
||
print("Location: SITER")
|
||
print("=" * 70)
|
||
|
||
print("\nGround mount advantages at your site:")
|
||
print(" - No trees = minimal shading losses")
|
||
print(" - Open rack = better airflow, cooler panels")
|
||
print(" - Optimal tilt (30°) = maximum annual production")
|
||
print()
|
||
|
||
# Standard 14% losses vs optimized 8% losses (no shade)
|
||
for losses in [14, 10, 8, 5]:
|
||
data = query(4.0, losses)
|
||
if data and not data.get("errors"):
|
||
annual = data["outputs"]["ac_annual"]
|
||
monthly = annual / 12
|
||
value = (annual * 0.60 * 0.085) + (annual * 0.40 * 0.04)
|
||
payback = 4100 / (value / 12)
|
||
print(f"Losses @ {losses}%: {annual:,.0f} kWh/yr | ${value/12:.2f}/mo | Payback: {payback/12:.1f} yrs")
|
||
|
||
print()
|
||
print("=" * 70)
|
||
print("PANEL WATTAGE COMPARISON (Optimized @ 8% losses)")
|
||
print("=" * 70)
|
||
|
||
for watts in [250, 300, 350, 400, 450]:
|
||
capacity = (16 * watts) / 1000
|
||
data = query(capacity, 8) # Optimized losses
|
||
if data and not data.get("errors"):
|
||
annual = data["outputs"]["ac_annual"]
|
||
value = (annual * 0.60 * 0.085) + (annual * 0.40 * 0.04)
|
||
payback = 4100 / (value / 12)
|
||
offset = (value / 12 / 301.08) * 100
|
||
print(f"16 × {watts}W ({capacity:.1f}kW): {annual:,.0f} kWh/yr | ${value/12:.2f}/mo | {offset:.0f}% offset | {payback/12:.1f} yr payback")
|