mudassarrafique commited on
Commit
2c3aca4
·
verified ·
1 Parent(s): 67f40a1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +107 -130
app.py CHANGED
@@ -1,150 +1,127 @@
1
  import streamlit as st
2
  import pandas as pd
3
- import datetime
4
  import plotly.graph_objects as go
5
- from difflib import get_close_matches
6
- import time
7
-
8
- # Function to standardize and find the closest column name
9
- def get_closest_column(columns, target, threshold=0.6):
10
- target = target.lower().replace(" ", "").replace("(", "").replace(")", "").replace("-", "")
11
- columns_cleaned = [col.lower().replace(" ", "").replace("(", "").replace(")", "").replace("-", "") for col in columns]
12
- matches = get_close_matches(target, columns_cleaned, n=1, cutoff=threshold)
13
- if matches:
14
- return columns[columns_cleaned.index(matches[0])]
15
- return None
16
 
17
- # Load the dataset
18
- @st.cache_data
19
  def load_data():
20
- try:
21
- df = pd.read_excel("grid_load_data.xlsx")
22
-
23
- # Identify the closest matches for required columns
24
- grid_load_col = get_closest_column(df.columns, "Grid Load (kW)")
25
- time_col = get_closest_column(df.columns, "Time")
26
-
27
- if not grid_load_col or not time_col:
28
- st.error("The dataset must include columns similar to 'Grid Load (kW)' and 'Time'. Please check the formatting.")
29
- return None, None
30
-
31
- # Rename columns for consistent processing
32
- df = df.rename(columns={grid_load_col: "Grid Load (kW)", time_col: "Time"})
33
-
34
- # Ensure 'Time' column is datetime formatted
35
- df["Time"] = pd.to_datetime(df["Time"], errors="coerce")
36
- return df, "Grid Load (kW)"
37
 
38
- except FileNotFoundError:
39
- st.error("The file 'grid_load_data.xlsx' was not found. Please upload the correct file.")
40
- return None, None
41
- except Exception as e:
42
- st.error(f"An error occurred while loading the dataset: {e}")
43
- return None, None
44
-
45
- # Function to calculate the predicted grid load for the current hour of the day
46
- def calculate_predicted_grid_load(df, current_time, grid_load_col):
47
- if df is None:
48
- st.error("Dataset is not loaded correctly.")
49
- return None
50
-
51
- # Extract the hour and day from the current time
52
  current_hour = current_time.hour
53
-
54
- # Filter dataset for the given hour across all days
55
- df["Hour"] = df["Time"].dt.hour
56
- hourly_data = df[df["Hour"] == current_hour]
57
-
58
- if not hourly_data.empty:
59
- # Calculate the average grid load for the given hour across all days
60
- avg_grid_load = hourly_data[grid_load_col].mean()
61
- return avg_grid_load
 
 
 
 
 
 
 
 
62
  else:
63
- st.warning("No data found for the current hour. Using default value.")
64
- return 0 # Default to 0 if no data is found for the given hour
65
-
66
- # Display live clock
67
- def display_clock():
68
- current_time = datetime.datetime.now()
69
- st.sidebar.markdown(f"### 🕒 {current_time.strftime('%Y-%m-%d %H:%M:%S')}")
70
- return current_time
71
-
72
- # Create Gauge meter
73
- def create_gauge(value):
74
  fig = go.Figure(go.Indicator(
75
- mode="gauge+number",
76
- value=value,
77
- title={'text': "Grid Load (kW)"},
78
  gauge={
79
  'axis': {'range': [0, 5000]},
80
- 'bar': {'color': "lightgray"},
81
  'steps': [
82
- {'range': [0, 1700], 'color': "lightcoral"},
83
- {'range': [1700, 3400], 'color': "lightgreen"},
84
- {'range': [3400, 5000], 'color': "red"}
85
  ],
86
- 'threshold': {
87
- 'line': {'color': "black", 'width': 4},
88
- 'thickness': 0.75,
89
- 'value': value
90
- }
91
- }
92
  ))
93
- fig.update_layout(margin={'l': 0, 'r': 0, 't': 0, 'b': 0}, height=400)
94
  return fig
95
 
96
- # Main app
97
- def main():
98
- st.title("Optimized EV Charging and Grid Management")
99
-
100
- # Load dataset
101
- df, grid_load_col = load_data()
102
- if df is None or grid_load_col is None:
103
- return # Exit if the dataset is not loaded properly
104
-
105
- # Sidebar for user inputs
106
- with st.sidebar:
107
- st.header("User Inputs")
108
-
109
- # Battery details (manually entered)
110
- state_of_charge = st.number_input("State of Charge (SOC) in kWh", min_value=0, max_value=100, step=1)
111
- battery_capacity = st.number_input("Battery Capacity (kWh)", min_value=10, max_value=200, step=1)
112
-
113
- # ON/OFF button for exporting battery power to the grid
114
- export_power = st.checkbox("Export Power to Grid (ON/OFF)")
115
-
116
- # Display live clock
117
- current_time = display_clock()
118
-
119
- # Predicted grid load
120
- predicted_grid_load = calculate_predicted_grid_load(df, current_time, grid_load_col)
121
- if predicted_grid_load is not None:
122
- st.write(f"### Predicted Grid Load at {current_time.strftime('%H:%M:%S')}: **{predicted_grid_load:.2f} kW**")
123
-
124
- # Create gauge meter based on grid load
125
- st.plotly_chart(create_gauge(predicted_grid_load))
126
-
127
- # Evaluate grid status based on the predicted load
128
- if predicted_grid_load > 3400:
129
- st.error("Grid is Overloaded! EV Charging Disallowed")
130
- st.write("🚫 Red Light: EV Charging is Disconnected.")
131
- elif predicted_grid_load <= 3400 and predicted_grid_load > 1700:
132
- st.success("Grid is Stable! EV Charging Allowed")
133
- st.write("✅ Green Light: EV Charging is Active.")
134
- else:
135
- st.warning("Grid is Low! EV Charging Allowed")
136
- st.write("🟠 Light Red Light: EV Charging is Active, but Grid is Low.")
137
-
138
- # Calculate available EV slots
139
- available_capacity = 3400 - predicted_grid_load
140
- ev_slots = available_capacity // 50 # Assuming each EV slot requires 50kW
141
- st.write(f"### Available EV Slots: **{ev_slots}**")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
- # Export power status
144
- if export_power:
145
- st.warning("Battery is exporting power to the grid.")
146
- else:
147
- st.info("Battery is not exporting power.")
 
148
 
149
  if __name__ == "__main__":
150
  main()
 
1
  import streamlit as st
2
  import pandas as pd
3
+ import numpy as np
4
  import plotly.graph_objects as go
5
+ import datetime
 
 
 
 
 
 
 
 
 
 
6
 
7
+ # Load dataset function
 
8
  def load_data():
9
+ # Ensure this path is correct for your environment
10
+ df = pd.read_excel("grid_load_data.xlsx")
11
+ return df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ # Calculate grid load based on time and dataset
14
+ def calculate_grid_load(df, current_time):
 
 
 
 
 
 
 
 
 
 
 
 
15
  current_hour = current_time.hour
16
+ hourly_load = df[df["Time"].dt.hour == current_hour]["Grid Load (kW)"].mean()
17
+ return hourly_load
18
+
19
+ # Create a gauge chart for grid load status
20
+ def create_gauge(load_value):
21
+ # Define ranges for low, normal, high
22
+ ranges = [0, 2000, 3000, 4000]
23
+ colors = ['lightgreen', 'green', 'red']
24
+ labels = ['Low', 'Normal', 'High']
25
+
26
+ # Determine color and range based on load value
27
+ if load_value < 2000:
28
+ color = colors[0]
29
+ range_label = labels[0]
30
+ elif load_value < 3000:
31
+ color = colors[1]
32
+ range_label = labels[1]
33
  else:
34
+ color = colors[2]
35
+ range_label = labels[2]
36
+
37
+ # Create the gauge chart using plotly
 
 
 
 
 
 
 
38
  fig = go.Figure(go.Indicator(
39
+ mode="gauge+number+delta",
40
+ value=load_value,
41
+ domain={'x': [0, 1], 'y': [0, 1]},
42
  gauge={
43
  'axis': {'range': [0, 5000]},
44
+ 'bar': {'color': color},
45
  'steps': [
46
+ {'range': [0, 2000], 'color': 'lightgreen'},
47
+ {'range': [2000, 3000], 'color': 'green'},
48
+ {'range': [3000, 5000], 'color': 'red'}
49
  ],
50
+ },
51
+ title={'text': f"Grid Load Status: {range_label}"},
52
+ delta={'reference': 2000}
 
 
 
53
  ))
 
54
  return fig
55
 
56
+ # Function to calculate the required EVs for grid stabilization
57
+ def calculate_ev_requirements(grid_load, ev_capacity=80, ev_efficiency=0.85):
58
+ # Assuming each EV contributes its battery capacity (80kWh) and efficiency (85%).
59
+ # Formula: EVs required = Grid load / (EV capacity * efficiency)
60
+ evs_needed = grid_load / (ev_capacity * ev_efficiency)
61
+ return np.ceil(evs_needed) # Round to the nearest whole number
62
+
63
+ # Function to calculate power and energy consumption from EV during underload condition
64
+ def calculate_ev_power_consumption(ev_capacity=80, charge_rate=0.85):
65
+ # Power consumed per EV during underload (assuming 85% depth of charge)
66
+ power_consumed = ev_capacity * charge_rate
67
+ return power_consumed
68
+
69
+ # Display the grid load prediction and related EV info
70
+ def display_grid_load_prediction_and_ev_info():
71
+ st.header("Grid Load Prediction and EV Charging Info")
72
+
73
+ # Allow user to manually set grid load using slider (0 to 5000 kW)
74
+ grid_load = st.slider(
75
+ "Select Grid Load (kW):",
76
+ min_value=0,
77
+ max_value=5000,
78
+ value=2000, # Default value
79
+ step=100,
80
+ help="Drag the slider to set the desired grid load."
81
+ )
82
+
83
+ # Display the gauge chart based on selected load value
84
+ st.plotly_chart(create_gauge(grid_load), use_container_width=True)
85
+
86
+ # LED Indicators for overload/normal status
87
+ if grid_load > 3500:
88
+ st.markdown('<p style="color: red; font-size: 24px;">&#128313; Left LED: Overload! Grid is in danger.</p>', unsafe_allow_html=True)
89
+ else:
90
+ st.markdown('<p style="color: green; font-size: 24px;">&#128313; Right LED: Normal. Grid is stable.</p>', unsafe_allow_html=True)
91
+
92
+ # EV Charging Status
93
+ if grid_load < 3000:
94
+ st.markdown('<p style="color: green;">Green: Charging allowed. EVs can charge.</p>', unsafe_allow_html=True)
95
+ # Calculate and display the number of EVs that can be connected based on grid load
96
+ evs_connected = calculate_ev_requirements(grid_load)
97
+ st.write(f"Approximately {evs_connected} EVs can be connected to the grid for charging.")
98
+
99
+ else:
100
+ st.markdown('<p style="color: red;">Red: Grid overload! Disconnecting EV from grid.</p>', unsafe_allow_html=True)
101
+ # If the load exceeds 3500 kW, calculate how much energy is needed to stabilize the grid
102
+ if grid_load > 3500:
103
+ energy_required = grid_load - 3500
104
+ evs_needed = calculate_ev_requirements(energy_required)
105
+ st.write(f"To stabilize the grid, {energy_required} kWh of energy is required.")
106
+ st.write(f"Approximately {evs_needed} EVs are needed to supply this energy to the grid.")
107
+
108
+ # Add a button to connect EVs to stabilize the grid
109
+ if st.button("Connect EVs to Stabilize Grid"):
110
+ grid_load -= energy_required # Decrease grid load by the energy provided by EVs
111
+ st.write(f"Grid load reduced to {grid_load} kW. EVs are stabilizing the grid.")
112
+
113
+ # Allow the user to disconnect EVs if the grid load is too high
114
+ if grid_load > 3000:
115
+ st.button("Disconnect EV from Grid", key="disconnect_charge", help="Grid load is too high. Disconnect EV.")
116
+ else:
117
+ st.button("Allow EV to Charge", key="allow_charge", help="Grid load is normal. EVs can charge.")
118
 
119
+ # Display Main Application
120
+ def main():
121
+ st.sidebar.title("EV Charging Optimization")
122
+
123
+ # Display the Grid Load Prediction and EV Info all on the same page
124
+ display_grid_load_prediction_and_ev_info()
125
 
126
  if __name__ == "__main__":
127
  main()