solar_savings / app.py
charagu-eric's picture
refined
d1cd9d0
raw
history blame
8.46 kB
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import streamlit as st
from typing import Dict
# Constants
ONE_BR_UNITS = 23
TWO_BR_UNITS = 45
SOLAR_PANEL_RATING = 625 # W
BATTERY_CAPACITY = 200 # Ah
BATTERY_VOLTAGE = 12 # V
SYSTEM_LOSSES = 0.20
FEED_IN_TARIFF = 12
# Lighting specifications
LIGHTS_1BR = 5
LIGHTS_2BR = 8
LIGHT_POWER = 6 # Watts per light
def initialize_session_state():
"""Initialize session state variables"""
defaults = {
'solar_panels': 100,
'batteries': 50,
'panel_price': 13000,
'battery_price': 39000,
'grid_price': 28.44
}
for key, value in defaults.items():
if key not in st.session_state:
st.session_state[key] = value
def calculate_lighting_consumption(occupancy_1br: float, occupancy_2br: float) -> float:
"""Calculate daily lighting consumption"""
return (
(occupancy_1br * ONE_BR_UNITS * LIGHTS_1BR * LIGHT_POWER / 1000) +
(occupancy_2br * TWO_BR_UNITS * LIGHTS_2BR * LIGHT_POWER / 1000)
) * 24 # Daily kWh
def calculate_appliance_consumption(occupancy_1br: float, occupancy_2br: float) -> float:
"""Calculate daily appliance consumption"""
return (
(occupancy_1br * ONE_BR_UNITS * (250 - (LIGHTS_1BR * LIGHT_POWER * 24 / 1000))) +
(occupancy_2br * TWO_BR_UNITS * (400 - (LIGHTS_2BR * LIGHT_POWER * 24 / 1000)))
) # Daily kWh
def total_consumption(occupancy_1br: float, occupancy_2br: float, common_area: float) -> float:
"""Calculate total monthly consumption"""
lighting = calculate_lighting_consumption(occupancy_1br, occupancy_2br)
appliances = calculate_appliance_consumption(occupancy_1br, occupancy_2br)
return (lighting + appliances + common_area) * 30 # Monthly kWh
def solar_production(panels: int) -> float:
"""Monthly solar production with losses"""
return panels * SOLAR_PANEL_RATING * 5 * 0.8 * 30 / 1000 # 5 sun hours
def battery_storage(batteries: int) -> float:
"""Usable battery capacity"""
return batteries * BATTERY_CAPACITY * BATTERY_VOLTAGE * 0.8 / 1000
def financial_analysis(consumption: float, production: float, storage: float) -> Dict:
"""Detailed financial calculations"""
solar_used = min(production, consumption)
grid_purchased = max(consumption - solar_used - storage, 0)
return {
'solar_contribution': solar_used / consumption * 100,
'grid_dependency': grid_purchased / consumption * 100,
'monthly_savings': (consumption * st.session_state.grid_price) -
(grid_purchased * st.session_state.grid_price),
'payback_period': (st.session_state.solar_panels * st.session_state.panel_price +
st.session_state.batteries * st.session_state.battery_price) /
((consumption - grid_purchased) * st.session_state.grid_price * 12)
}
def create_consumption_breakdown(occupancy_1br: float, occupancy_2br: float, common_area: float):
"""Create detailed consumption breakdown"""
breakdown = {
'Lighting': calculate_lighting_consumption(occupancy_1br, occupancy_2br) * 30,
'Appliances': calculate_appliance_consumption(occupancy_1br, occupancy_2br) * 30,
'Common Areas': common_area * 30
}
return pd.DataFrame.from_dict(breakdown, orient='index', columns=['kWh'])
# Streamlit Interface
def main():
st.set_page_config("Solar Analysis Suite", "🌞", "wide")
initialize_session_state()
st.title("🌞 Advanced Solar Performance Analyzer")
with st.sidebar:
st.header("System Configuration")
st.number_input("Solar Panels", 1, 1000, key='solar_panels')
st.number_input("Batteries", 0, 500, key='batteries')
st.number_input("Panel Price (Ksh)", 1000, 50000, key='panel_price')
st.number_input("Battery Price (Ksh)", 5000, 100000, key='battery_price')
st.number_input("Grid Price (Ksh/kWh)", 10.0, 50.0, key='grid_price')
scenarios = {
"Low Occupancy": {"1br": 0.0, "2br": 1.0, "common": 5.904},
"Medium Occupancy": {"1br": 0.25, "2br": 1.0, "common": 5.904},
"High Occupancy": {"1br": 0.5, "2br": 1.0, "common": 5.904}
}
analysis_data = []
for name, params in scenarios.items():
consumption = total_consumption(
params["1br"], params["2br"], params["common"]
)
production = solar_production(st.session_state.solar_panels)
storage = battery_storage(st.session_state.batteries)
financials = financial_analysis(consumption, production, storage)
analysis_data.append({
"Scenario": name,
"Consumption": consumption,
"Production": production,
**financials
})
df = pd.DataFrame(analysis_data)
# Energy Flow Analysis
st.header("Energy Flow Composition")
fig, ax = plt.subplots(figsize=(10, 6))
sns.barplot(df.melt(id_vars=['Scenario'],
value_vars=['solar_contribution', 'grid_dependency'],
x='Scenario', y='value', hue='variable', ax=ax)
ax.set_ylabel("Percentage (%)")
ax.set_title("Energy Contribution Breakdown")
st.pyplot(fig)
with st.expander("🔍 Energy Flow Interpretation"):
st.markdown("""
**Understanding the Chart:**
- **Solar Contribution**: Percentage of total energy needs met by solar production
- **Grid Dependency**: Remaining energy required from grid
- Ideal scenario shows high solar contribution with minimal grid dependency
""")
# Financial Analysis
st.header("Financial Performance Metrics")
# Metric 1: Monthly Savings
fig1, ax1 = plt.subplots(figsize=(10, 4))
sns.barplot(data=df, x='Scenario', y='monthly_savings', ax=ax1)
ax1.set_title("Monthly Cost Savings")
ax1.set_ylabel("Ksh")
st.pyplot(fig1)
with st.expander("💵 Savings Analysis"):
st.markdown(f"""
**Key Observations:**
- Savings calculated as: `(Total Consumption × Grid Price) - (Grid Purchased × Grid Price)`
- Current Grid Price: Ksh {st.session_state.grid_price}/kWh
- Maximum potential savings limited by solar production capacity
""")
st.table(df[['Scenario', 'Consumption', 'Production', 'monthly_savings']])
# Metric 2: Payback Period
fig2, ax2 = plt.subplots(figsize=(10, 4))
sns.barplot(data=df, x='Scenario', y='payback_period', ax=ax2)
ax2.set_title("System Payback Period")
ax2.set_ylabel("Years")
st.pyplot(fig2)
with st.expander("⏳ Payback Explanation"):
st.markdown(f"""
**Calculation Methodology:**
- Total Investment: (Panels × {st.session_state.panel_price:,}Ksh) + (Batteries × {st.session_state.battery_price:,}Ksh)
- Annual Savings: Monthly Savings × 12
- Payback Period = Total Investment / Annual Savings
""")
st.table(df[['Scenario', 'payback_period']])
# Consumption Breakdown
st.header("Detailed Consumption Analysis")
scenario_select = st.selectbox("Select Scenario", list(scenarios.keys()))
selected_params = scenarios[scenario_select]
breakdown_df = create_consumption_breakdown(
selected_params["1br"],
selected_params["2br"],
selected_params["common"]
)
col1, col2 = st.columns(2)
with col1:
st.subheader("Energy Composition")
fig3, ax3 = plt.subplots()
breakdown_df.plot.pie(y='kWh', ax=ax3, autopct='%1.1f%%')
st.pyplot(fig3)
with col2:
st.subheader("Component Breakdown")
st.table(breakdown_df)
analysis_text = f"""
**Key Insights for {scenario_select}:**
- Lighting contributes {breakdown_df.loc['Lighting', 'kWh']/breakdown_df.sum().values[0]*100:.1f}% of total consumption
- Common areas account for {breakdown_df.loc['Common Areas', 'kWh']:.0f}kWh monthly
- 2BR units dominate appliance usage at {selected_params['2br']*100}% occupancy
"""
st.markdown(analysis_text)
if __name__ == "__main__":
main()