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")