import streamlit as st
import pandas as pd
import numpy as np
import math
import matplotlib.pyplot as plt
import numpy_financial as npf
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet
import io
import xlsxwriter
# ===============================
# CONFIGURATION
# ===============================
SYSTEM_LOSSES = 0.20
PANEL_COST_PER_WATT = 55
INSTALLATION_COST_PER_WATT = 35
LITHIUM_BATTERY_COST_5KWH = 95000
CITY_SUNLIGHT = {
"Karachi": 6.2,
"Lahore": 5.5,
"Islamabad": 5.2,
"Peshawar": 5.6,
"Quetta": 6.5,
}
APPLIANCES_RESIDENTIAL = {
"LED Bulb (12W)": 12,
"Fan (80W)": 80,
"Refrigerator (200W)": 200,
"LED TV (150W)": 150,
"Air Conditioner 1.5 Ton (1500W)": 1500,
"Washing Machine (500W)": 500,
"Water Pump (750W)": 750,
"Laptop (65W)": 65,
"Iron (1000W)": 1000,
}
APPLIANCES_COMMERCIAL = {
"CNC Machine (2kW)": 2000,
"Industrial AC (5kW)": 5000,
"Lighting System (1kW)": 1000,
"Water Pump 3HP (2.2kW)": 2200,
"Server Rack (1.5kW)": 1500,
}
RESIDENTIAL_TARIFF = [
(100, 22),
(100, 32),
(100, 38),
(100, 42),
(100, 48),
(np.inf, 65),
]
COMMERCIAL_TARIFF = 72 # PKR/unit average
# ===============================
# FUNCTIONS
# ===============================
def calculate_residential_bill(units):
remaining = units
bill = 0
for slab_units, rate in RESIDENTIAL_TARIFF:
if remaining > slab_units:
bill += slab_units * rate
remaining -= slab_units
else:
bill += remaining * rate
break
return bill
def calculate_commercial_bill(units):
return units * COMMERCIAL_TARIFF
def calculate_system(load_watts, hours, sunlight):
daily_kwh = (load_watts * hours) / 1000
adjusted_kwh = daily_kwh / (1 - SYSTEM_LOSSES)
required_kw = adjusted_kwh / sunlight
return daily_kwh, round(required_kw, 2)
def calculate_battery(daily_kwh, backup_hours):
backup_kwh = (daily_kwh / 24) * backup_hours
batteries = math.ceil(backup_kwh / 5)
return batteries
def calculate_cost(system_kw, batteries, system_type):
base_cost = system_kw * 1000 * (PANEL_COST_PER_WATT + INSTALLATION_COST_PER_WATT)
battery_cost = batteries * LITHIUM_BATTERY_COST_5KWH
if system_type == "On-Grid":
return base_cost
elif system_type == "Off-Grid":
return base_cost + battery_cost
else:
return base_cost * 1.1 + battery_cost
def emi_calculator(principal, annual_rate, years):
r = annual_rate / 100 / 12
n = years * 12
emi = principal * r * (1 + r)**n / ((1 + r)**n - 1)
return round(emi)
def financial_projection(total_cost, daily_kwh, mode, years=25, inflation_rate=5, energy_price_increase=7):
monthly_units = daily_kwh * 30
cashflows = []
for year in range(1, years+1):
if mode == "Homeowner":
monthly_bill = calculate_residential_bill(monthly_units * ((1 + energy_price_increase/100)**(year-1)))
else:
monthly_bill = calculate_commercial_bill(monthly_units * ((1 + energy_price_increase/100)**(year-1)))
annual_savings = monthly_bill * 12
cashflows.append(annual_savings)
npv = npf.npv(inflation_rate/100, [-total_cost]+cashflows)
irr = npf.irr([-total_cost]+cashflows)
payback_year = next((i for i, cf in enumerate(np.cumsum(cashflows), 1) if cf >= total_cost), None)
cumulative_savings = np.cumsum(cashflows)
return cashflows, round(npv,2), round(irr*100,2), payback_year, cumulative_savings
def generate_pdf(report_data):
file_path = "solar_report.pdf"
doc = SimpleDocTemplate(file_path, pagesize=A4)
elements = []
styles = getSampleStyleSheet()
elements.append(Paragraph("Pakistan Solar Feasibility Report", styles['Title']))
elements.append(Spacer(1, 12))
for key, value in report_data.items():
elements.append(Paragraph(f"{key}: {value}", styles['Normal']))
elements.append(Spacer(1, 8))
doc.build(elements)
return file_path
def generate_excel(report_data):
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output)
worksheet = workbook.add_worksheet("Solar Report")
bold = workbook.add_format({'bold': True})
row = 0
for key, value in report_data.items():
worksheet.write(row, 0, key, bold)
worksheet.write(row, 1, str(value))
row += 1
workbook.close()
output.seek(0)
return output
# ===============================
# STREAMLIT APP
# ===============================
st.set_page_config(layout="wide")
st.title("🇵🇰 Pakistan Solar Engineering & Financial Dashboard")
audience = st.selectbox("Select Audience", ["Homeowner", "Solar Company", "Industrial Investor"])
city = st.selectbox("Select City", list(CITY_SUNLIGHT.keys()))
sunlight = CITY_SUNLIGHT[city]
if audience == "Homeowner":
appliances = st.multiselect("Select Appliances", list(APPLIANCES_RESIDENTIAL.keys()))
elif audience == "Solar Company":
appliances = st.multiselect("Select Residential / Commercial Appliances",
list(APPLIANCES_RESIDENTIAL.keys()) + list(APPLIANCES_COMMERCIAL.keys()))
else:
appliances = st.multiselect("Select Industrial Equipment", list(APPLIANCES_COMMERCIAL.keys()))
hours = st.slider("Usage Hours per Day", 1, 24, 8)
system_type = st.radio("System Type", ["On-Grid", "Off-Grid", "Hybrid"])
backup_hours = st.slider("Battery Backup Hours", 0, 24, 4)
if st.button("Calculate Solar System"):
if not appliances:
st.error("Please select at least one appliance or equipment")
else:
total_load = sum(APPLIANCES_RESIDENTIAL.get(a,0) + APPLIANCES_COMMERCIAL.get(a,0) for a in appliances)
daily_kwh, system_kw = calculate_system(total_load, hours, sunlight)
batteries = calculate_battery(daily_kwh, backup_hours)
total_cost = calculate_cost(system_kw, batteries, system_type)
interest = st.slider("Bank Interest Rate (%)", 5, 25, 15)
years_loan = st.slider("Loan Duration (Years)", 1, 10, 5)
emi = emi_calculator(total_cost, interest, years_loan)
cashflows, npv, irr, payback_year, cumulative_savings = financial_projection(total_cost, daily_kwh, audience)
# Display Results
st.subheader("System Analysis")
st.write(f"Total Load: {total_load} W")
st.write(f"Daily Energy Consumption: {round(daily_kwh,2)} kWh")
st.write(f"Required System Size: {system_kw} kW")
st.write(f"Battery Units Required (5kWh each): {batteries}")
st.write(f"Estimated System Cost: PKR {round(total_cost):,}")
st.write(f"EMI (Monthly): PKR {emi:,}")
st.write(f"25-Year Projection: NPV = PKR {npv:,}, IRR = {irr}%, Payback Year = {payback_year}")
# Dashboard
st.subheader("🔹 Daily Load vs Solar Generation")
hours_day = np.arange(0,24,1)
load_profile = np.array([total_load]*24)
solar_profile = np.array([system_kw*1000/sunlight]*24)
plt.figure(figsize=(10,4))
plt.plot(hours_day, load_profile, label="Load (W)")
plt.plot(hours_day, solar_profile, label="Solar Generation (W)")
plt.xlabel("Hour of Day")
plt.ylabel("Power (W)")
plt.title("Daily Load vs Solar Generation")
plt.legend()
st.pyplot(plt)
st.subheader("🔹 Cumulative Savings Over 25 Years")
plt.figure(figsize=(10,4))
plt.plot(range(1,26), cumulative_savings, marker='o')
plt.axhline(total_cost, color='r', linestyle='--', label="Total System Cost")
plt.xlabel("Year")
plt.ylabel("Cumulative Savings (PKR)")
plt.title("Payback & Savings Curve")
plt.legend()
st.pyplot(plt)
st.subheader("🔹 Yearly Cashflows")
df_cashflow = pd.DataFrame({"Year": range(1,26), "Annual Savings (PKR)": cashflows})
st.dataframe(df_cashflow)
st.subheader("🔹 Carbon Emission Reduction Estimate")
co2_per_kwh = 0.85
total_co2_saved = round(daily_kwh * 365 * 25 * co2_per_kwh)
st.write(f"Estimated CO2 Reduction over 25 years: {total_co2_saved:,} kg (~{total_co2_saved/1000:,} tons)")
# PDF & Excel
report_data = {
"Audience": audience,
"City": city,
"System Type": system_type,
"Total Load (W)": total_load,
"Daily Energy (kWh)": round(daily_kwh,2),
"System Size (kW)": system_kw,
"Battery Units": batteries,
"Total Cost (PKR)": round(total_cost),
"EMI (PKR)": emi,
"25-Year NPV (PKR)": npv,
"IRR (%)": irr,
"Payback Year": payback_year
}
pdf_file = generate_pdf(report_data)
excel_file = generate_excel(report_data)
with open(pdf_file, "rb") as f:
st.download_button("Download PDF Report", f, file_name="Solar_Report_Pakistan.pdf")
st.download_button("Download Excel Report", data=excel_file, file_name="Solar_Report_Pakistan.xlsx")