import streamlit as st import pandas as pd import numpy as np from datetime import datetime, timedelta import plotly.express as px import plotly.graph_objects as go from sklearn.ensemble import IsolationForest from sklearn.linear_model import LinearRegression import random import calendar # Set random seed for reproducibility np.random.seed(42) def generate_device_data(num_days=90, device_type="home"): """Generate synthetic energy consumption data for devices with enhanced patterns""" dates = pd.date_range(end=datetime.now(), periods=num_days*24, freq='h') if device_type == "home": devices = { 'HVAC': {'base': 8, 'var': 4, 'peak_hours': [14, 15, 16, 17], 'weekend_factor': 1.2}, 'Refrigerator': {'base': 2, 'var': 0.5, 'peak_hours': [12, 13, 14], 'weekend_factor': 1.0}, 'Washing Machine': {'base': 1, 'var': 0.8, 'peak_hours': [10, 19, 20], 'weekend_factor': 1.5}, 'Lighting': {'base': 1.5, 'var': 0.3, 'peak_hours': [18, 19, 20, 21], 'weekend_factor': 1.1}, 'Television': {'base': 0.5, 'var': 0.2, 'peak_hours': [20, 21, 22], 'weekend_factor': 1.3} } else: devices = { 'HVAC System': {'base': 20, 'var': 8, 'peak_hours': [14, 15, 16, 17], 'weekend_factor': 0.6}, 'Server Room': {'base': 15, 'var': 3, 'peak_hours': [12, 13, 14], 'weekend_factor': 0.9}, 'Office Equipment': {'base': 10, 'var': 4, 'peak_hours': [9, 10, 11, 14, 15], 'weekend_factor': 0.4}, 'Lighting': {'base': 8, 'var': 2, 'peak_hours': [9, 10, 11, 14, 15], 'weekend_factor': 0.5}, 'Kitchen Appliances': {'base': 5, 'var': 2, 'peak_hours': [12, 13], 'weekend_factor': 0.3} } data = [] for date in dates: hour = date.hour is_weekend = date.weekday() >= 5 for device, params in devices.items(): # Add seasonal variation seasonal_factor = 1 + 0.3 * np.sin(2 * np.pi * date.dayofyear / 365) # Add peak hour variation peak_factor = 1.5 if hour in params['peak_hours'] else 1 # Add weekend variation weekend_factor = params['weekend_factor'] if is_weekend else 1 # Base consumption with random variation consumption = (params['base'] * seasonal_factor * peak_factor * weekend_factor + np.random.normal(0, params['var'])) # Add some anomalies (3% chance) if np.random.random() < 0.03: consumption *= np.random.choice([1.5, 2.0, 0.5]) data.append({ 'Date': date, 'Device': device, 'Consumption': max(0, consumption), 'Hour': hour, 'Weekday': date.strftime('%A'), 'Weekend': is_weekend }) return pd.DataFrame(data) def detect_anomalies(df): """Enhanced anomaly detection using Isolation Forest with multiple features""" iso_forest = IsolationForest(contamination=0.03, random_state=42) by_device = df.groupby('Device') anomalies = [] for device, group in by_device: # Use multiple features for anomaly detection features = group[['Consumption', 'Hour']].copy() features['Weekend'] = group['Weekend'].astype(int) predictions = iso_forest.fit_predict(features) anomaly_indices = predictions == -1 anomaly_data = group[anomaly_indices] for _, row in anomaly_data.iterrows(): anomalies.append({ 'Device': device, 'Date': row['Date'], 'Consumption': row['Consumption'], 'Hour': row['Hour'], 'Weekday': row['Weekday'] }) return pd.DataFrame(anomalies) def generate_insights(df): """Generate detailed insights from the energy consumption data""" insights = [] # Peak usage analysis peak_hours = df.groupby(['Device', 'Hour'])['Consumption'].mean().reset_index() for device in df['Device'].unique(): device_peaks = peak_hours[peak_hours['Device'] == device].nlargest(3, 'Consumption') insights.append({ 'Type': 'Peak Hours', 'Device': device, 'Description': f"Peak usage hours: {', '.join(map(str, device_peaks['Hour']))}", 'Impact': 'High' }) # Weekend vs Weekday analysis weekend_comparison = df.groupby(['Device', 'Weekend'])['Consumption'].mean().unstack() for device in weekend_comparison.index: diff_pct = ((weekend_comparison.loc[device, True] - weekend_comparison.loc[device, False]) / weekend_comparison.loc[device, False] * 100) insights.append({ 'Type': 'Weekend Pattern', 'Device': device, 'Description': f"{'Higher' if diff_pct > 0 else 'Lower'} weekend usage by {abs(diff_pct):.1f}%", 'Impact': 'Medium' if abs(diff_pct) < 20 else 'High' }) return pd.DataFrame(insights) def predict_consumption(df, days_ahead=30): """Predict future consumption using linear regression with multiple features""" predictions = [] for device in df['Device'].unique(): device_data = df[df['Device'] == device].copy() # Create features for prediction device_data['Day_of_Week'] = device_data['Date'].dt.dayofweek device_data['Month'] = device_data['Date'].dt.month device_data['Day_of_Year'] = device_data['Date'].dt.dayofyear X = device_data[['Hour', 'Day_of_Week', 'Month', 'Day_of_Year']] y = device_data['Consumption'] model = LinearRegression() model.fit(X, y) # Generate future dates future_dates = pd.date_range( start=df['Date'].max() + timedelta(hours=1), periods=days_ahead*24, freq='h' ) future_X = pd.DataFrame({ 'Hour': future_dates.hour, 'Day_of_Week': future_dates.dayofweek, 'Month': future_dates.month, 'Day_of_Year': future_dates.dayofyear }) future_predictions = model.predict(future_X) for date, pred in zip(future_dates, future_predictions): predictions.append({ 'Date': date, 'Device': device, 'Predicted_Consumption': max(0, pred) }) return pd.DataFrame(predictions) # Streamlit UI st.set_page_config(page_title="SEMS - Smart Energy Management System", layout="wide", initial_sidebar_state="expanded") # Custom CSS st.markdown(""" """, unsafe_allow_html=True) st.title("đŸĸ SEMS - Smart Energy Management System") # Sidebar configuration st.sidebar.title("Configuration") user_type = st.sidebar.radio("Select User Type", ["Home", "Organization"]) analysis_period = st.sidebar.slider("Analysis Period (Days)", 30, 180, 90) # Generate data data = generate_device_data(num_days=analysis_period, device_type=user_type.lower()) # Main tabs tab1, tab2, tab3, tab4 = st.tabs([ "📊 Usage Dashboard", "🔍 Detailed Analysis", "⚠ī¸ Peak Usage Detection", "📈 Forecasting" ]) with tab1: st.header("Energy Usage Dashboard") # Key metrics col1, col2, col3 = st.columns(3) total_consumption = data['Consumption'].sum() avg_daily = data.groupby(data['Date'].dt.date)['Consumption'].sum().mean() peak_hour = data.groupby('Hour')['Consumption'].mean().idxmax() col1.metric("Total Consumption", f"{total_consumption:.1f} kWh") col2.metric("Average Daily Usage", f"{avg_daily:.1f} kWh") col3.metric("Peak Usage Hour", f"{peak_hour}:00") # Daily consumption trend st.subheader("Daily Consumption Trend") daily_consumption = data.groupby(['Date', 'Device'])['Consumption'].sum().reset_index() fig = px.line(daily_consumption, x='Date', y='Consumption', color='Device', title='Energy Consumption Over Time') fig.update_layout(height=400) st.plotly_chart(fig, use_container_width=True) # Device-wise distribution col1, col2 = st.columns(2) with col1: device_total = data.groupby('Device')['Consumption'].sum().sort_values(ascending=True) fig = px.bar(device_total, orientation='h', title='Total Consumption by Device') st.plotly_chart(fig, use_container_width=True) with col2: hourly_avg = data.groupby(['Hour', 'Device'])['Consumption'].mean().reset_index() fig = px.line(hourly_avg, x='Hour', y='Consumption', color='Device', title='Average Hourly Consumption Pattern') st.plotly_chart(fig, use_container_width=True) with tab2: st.header("Detailed Analysis") # Weekday vs Weekend analysis st.subheader("Weekday vs Weekend Consumption") weekly_pattern = data.groupby(['Weekday', 'Device'])['Consumption'].mean().reset_index() fig = px.bar(weekly_pattern, x='Weekday', y='Consumption', color='Device', title='Average Consumption by Day of Week') st.plotly_chart(fig, use_container_width=True) # Hourly heatmap st.subheader("Hourly Consumption Heatmap") hourly_data = data.pivot_table( values='Consumption', index='Hour', columns='Weekday', aggfunc='mean' ) fig = px.imshow(hourly_data, labels=dict(x="Day of Week", y="Hour of Day", color="Consumption"), aspect="auto", title="Consumption Intensity by Hour and Day") st.plotly_chart(fig, use_container_width=True) # Display insights st.subheader("Key Insights") insights = generate_insights(data) for _, insight in insights.iterrows(): with st.expander(f"{insight['Device']} - {insight['Type']} (Impact: {insight['Impact']})"): st.write(insight['Description']) with tab3: st.header("Peak Usage Detection") # Detect anomalies anomalies = detect_anomalies(data) if not anomalies.empty: st.warning(f"Detected {len(anomalies)} anomalies in energy consumption") # Plot with anomalies fig = go.Figure() for device in data['Device'].unique(): device_data = data[data['Device'] == device] device_anomalies = anomalies[anomalies['Device'] == device] fig.add_trace(go.Scatter( x=device_data['Date'], y=device_data['Consumption'], name=f"{device} (normal)", mode='lines' )) if not device_anomalies.empty: fig.add_trace(go.Scatter( x=device_anomalies['Date'], y=device_anomalies['Consumption'], name=f"{device} (anomaly)", mode='markers', marker=dict(size=10, symbol='x', color='red') )) fig.update_layout( title='Energy Consumption with Detected Anomalies', height=500 ) st.plotly_chart(fig, use_container_width=True) # Anomaly details in an expandable table st.subheader("Peak Usage Details") for device in anomalies['Device'].unique(): device_anomalies = anomalies[anomalies['Device'] == device].copy() device_anomalies['Date'] = device_anomalies['Date'].dt.strftime('%Y-%m-%d %H:%M') with st.expander(f"Anomalies for {device}"): st.dataframe( device_anomalies[['Date', 'Consumption', 'Hour', 'Weekday']], use_container_width=True ) with tab4: st.header("Consumption Forecasting") # Generate predictions predictions = predict_consumption(data) # Plot historical data and predictions st.subheader("Consumption Forecast") for device in predictions['Device'].unique(): with st.expander(f"Forecast for {device}"): historical = data[data['Device'] == device] device_predictions = predictions[predictions['Device'] == device] fig = go.Figure() # Historical data fig.add_trace(go.Scatter( x=historical['Date'], y=historical['Consumption'], name='Historical', line=dict(color='blue') )) # Predictions fig.add_trace(go.Scatter( x=device_predictions['Date'], y=device_predictions['Predicted_Consumption'], name='Forecast', line=dict(color='red', dash='dash') )) fig.update_layout( title=f'Energy Consumption Forecast - {device}', xaxis_title='Date', yaxis_title='Consumption (kWh)', height=400 ) st.plotly_chart(fig, use_container_width=True) # Summary statistics col1, col2, col3 = st.columns(3) avg_historical = historical['Consumption'].mean() avg_predicted = device_predictions['Predicted_Consumption'].mean() change_pct = (avg_predicted - avg_historical) / avg_historical * 100 col1.metric( "Average Historical Usage", f"{avg_historical:.2f} kWh" ) col2.metric( "Average Predicted Usage", f"{avg_predicted:.2f} kWh" ) col3.metric( "Expected Change", f"{change_pct:+.1f}%", delta_color="inverse" ) # Additional insights section st.subheader("Energy Saving Opportunities") # Calculate potential savings based on patterns def calculate_savings_opportunities(historical_data, predictions_data): opportunities = [] # Check for peak hour reduction potential peak_hours = historical_data.groupby('Hour')['Consumption'].mean() top_peak_hours = peak_hours.nlargest(3) potential_peak_savings = top_peak_hours.sum() * 0.2 # Assume 20% reduction possible opportunities.append({ 'Type': 'Peak Hour Reduction', 'Description': f'Reduce usage during peak hours ({", ".join(map(str, top_peak_hours.index))}:00)', 'Potential_Savings': f'{potential_peak_savings:.2f} kWh per day' }) # Check for weekend optimization weekend_data = historical_data[historical_data['Weekend']] weekday_data = historical_data[~historical_data['Weekend']] if weekend_data['Consumption'].mean() > weekday_data['Consumption'].mean(): weekend_savings = (weekend_data['Consumption'].mean() - weekday_data['Consumption'].mean()) * 2 opportunities.append({ 'Type': 'Weekend Optimization', 'Description': 'Optimize weekend consumption patterns', 'Potential_Savings': f'{weekend_savings:.2f} kWh per weekend' }) # Seasonal optimization seasonal_data = historical_data.copy() seasonal_data['Month'] = seasonal_data['Date'].dt.month monthly_avg = seasonal_data.groupby('Month')['Consumption'].mean() seasonal_variation = monthly_avg.max() - monthly_avg.min() if seasonal_variation > monthly_avg.mean() * 0.3: # If variation is more than 30% opportunities.append({ 'Type': 'Seasonal Optimization', 'Description': 'Implement seasonal usage strategies', 'Potential_Savings': f'{seasonal_variation:.2f} kWh per month' }) return pd.DataFrame(opportunities) savings_opportunities = calculate_savings_opportunities(data, predictions) for _, opportunity in savings_opportunities.iterrows(): with st.expander(f"💡 {opportunity['Type']}"): st.write(f"**Description:** {opportunity['Description']}") st.write(f"**Potential Savings:** {opportunity['Potential_Savings']}") # Add specific recommendations based on opportunity type if opportunity['Type'] == 'Peak Hour Reduction': st.write(""" **Recommendations:** - Schedule high-energy activities during off-peak hours - Use automated controls to limit non-essential usage during peak times - Consider energy storage solutions for peak shifting """) elif opportunity['Type'] == 'Weekend Optimization': st.write(""" **Recommendations:** - Review weekend device scheduling - Implement automatic shutdown for unused equipment - Optimize temperature settings for unoccupied periods """) elif opportunity['Type'] == 'Seasonal Optimization': st.write(""" **Recommendations:** - Adjust HVAC settings seasonally - Implement weather-based control strategies - Schedule maintenance during shoulder seasons """) # Add export functionality if st.sidebar.button("Export Analysis Report"): # Create report dataframe report_data = { 'Metric': [ 'Total Consumption', 'Average Daily Usage', 'Peak Usage Hour', 'Number of Anomalies', 'Forecast Trend' ], 'Value': [ f"{total_consumption:.1f} kWh", f"{avg_daily:.1f} kWh", f"{peak_hour}:00", len(anomalies), f"{change_pct:+.1f}% (30-day forecast)" ] } report_df = pd.DataFrame(report_data) # Convert to CSV csv = report_df.to_csv(index=False) st.sidebar.download_button( label="Download Report", data=csv, file_name="energy_analysis_report.csv", mime="text/csv" ) # Add help section in sidebar with st.sidebar.expander("ℹī¸ Help"): st.write(""" **Using the Dashboard:** 1. Select your user type (Home/Organization) 2. Adjust the analysis period using the slider 3. Navigate through tabs to view different analyses 4. Use expanders to see detailed information 5. Export your analysis report using the button above For additional support, contact our team at support@sems.com """) # Add system status st.sidebar.markdown("---") st.sidebar.markdown("### System Status") st.sidebar.markdown("✅ All Systems Operational") st.sidebar.markdown(f"Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")