Spaces:
Sleeping
Sleeping
File size: 6,281 Bytes
eca7f1c e46de05 eca7f1c b74770b eca7f1c b74770b eca7f1c 123019e eca7f1c 123019e eca7f1c e46de05 eca7f1c 311a549 eca7f1c b74770b eca7f1c e46de05 d29b50b e46de05 385e35b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
import random
import pandas as pd
import streamlit as st
import pydeck as pdk
from datetime import datetime, timedelta
import altair as alt
# ---- Constants ----
POLES_PER_SITE = 12
SITES = {
"Hyderabad": [17.385044, 78.486671],
"Gadwal": [16.2351, 77.8052],
"Kurnool": [15.8281, 78.0373],
"Ballari": [12.9716, 77.5946]
}
# ---- Helper Functions ----
def generate_location(base_lat, base_lon):
return [
base_lat + random.uniform(-0.02, 0.02),
base_lon + random.uniform(-0.02, 0.02)
]
def simulate_pole(pole_id, site_name):
lat, lon = generate_location(*SITES[site_name])
solar_kwh = round(random.uniform(3.0, 7.5), 2)
wind_kwh = round(random.uniform(0.5, 2.0), 2)
power_required = round(random.uniform(4.0, 8.0), 2)
total_power = solar_kwh + wind_kwh
power_status = 'Sufficient' if total_power >= power_required else 'Insufficient'
vibration = round(random.uniform(0, 5), 2)
camera_status = random.choice(['Online', 'Offline'])
alert_level = 'Green'
if vibration > 3:
alert_level = 'Yellow'
if vibration > 4.5:
alert_level = 'Red'
health_score = max(0, 100 - (vibration * 10))
timestamp = datetime.now() - timedelta(hours=random.randint(0, 6))
return {
'Pole ID': f'{site_name[:3].upper()}-{pole_id:03}',
'Site': site_name,
'Latitude': lat,
'Longitude': lon,
'Solar (kWh)': solar_kwh,
'Wind (kWh)': wind_kwh,
'Power Required (kWh)': power_required,
'Total Power (kWh)': total_power,
'Power Status': power_status,
'Vibration (g)': vibration,
'Camera Status': camera_status,
'Health Score': round(health_score, 2),
'Alert Level': alert_level,
'Last Checked': timestamp.strftime('%Y-%m-%d %H:%M:%S')
}
# ---- Streamlit UI ----
st.set_page_config(page_title="Smart Pole Monitoring", layout="wide")
st.title("π Smart Renewable Pole Monitoring - Multi-Site")
selected_site = st.selectbox("Select a site to view:", options=list(SITES.keys()), index=0)
if selected_site in SITES:
with st.spinner(f"Simulating poles at {selected_site}..."):
poles_data = [simulate_pole(i + 1, site) for site in SITES for i in range(POLES_PER_SITE)]
df = pd.DataFrame(poles_data)
site_df = df[df['Site'] == selected_site]
# Summary Metrics
col1, col2, col3 = st.columns(3)
col1.metric("Total Poles", site_df.shape[0])
col2.metric("Red Alerts", site_df[site_df['Alert Level'] == 'Red'].shape[0])
col3.metric("Power Insufficiencies", site_df[site_df['Power Status'] == 'Insufficient'].shape[0])
# Table View
st.subheader(f"π Pole Data Table for {selected_site}")
with st.expander("Filter Options"):
alert_filter = st.multiselect("Alert Level", options=site_df['Alert Level'].unique(), default=site_df['Alert Level'].unique())
camera_filter = st.multiselect("Camera Status", options=site_df['Camera Status'].unique(), default=site_df['Camera Status'].unique())
filtered_df = site_df[(site_df['Alert Level'].isin(alert_filter)) & (site_df['Camera Status'].isin(camera_filter))]
st.dataframe(filtered_df, use_container_width=True)
# ---- Energy Chart ----
st.subheader("π Energy Generation per Pole")
energy_long_df = site_df[['Pole ID', 'Solar (kWh)', 'Wind (kWh)']].melt(
id_vars='Pole ID',
value_vars=['Solar (kWh)', 'Wind (kWh)'],
var_name='Energy Source',
value_name='kWh'
)
bar_chart = alt.Chart(energy_long_df).mark_bar().encode(
x=alt.X('Pole ID:N', sort=None, title='Pole ID'),
y=alt.Y('kWh:Q'),
color='Energy Source:N',
tooltip=['Pole ID', 'Energy Source', 'kWh']
).properties(
width=800,
height=400
).configure_axisX(labelAngle=45)
st.altair_chart(bar_chart, use_container_width=True)
# ---- Fault Type Filter ----
st.subheader("β οΈ Map Filter: Select Fault Type(s)")
fault_options = ['High Vibration (>3g)', 'Camera Offline', 'Power Insufficient']
selected_faults = st.multiselect("Show poles with these fault conditions:", options=fault_options, default=fault_options)
def fault_condition(row):
return (
('High Vibration (>3g)' in selected_faults and row['Vibration (g)'] > 3) or
('Camera Offline' in selected_faults and row['Camera Status'] == 'Offline') or
('Power Insufficient' in selected_faults and row['Power Status'] == 'Insufficient')
)
fault_df = site_df[site_df.apply(fault_condition, axis=1)] if selected_faults else site_df
# ---- Map Color Logic ----
def get_color(alert):
if alert == 'Green':
return [0, 255, 0, 160]
elif alert == 'Yellow':
return [255, 255, 0, 160]
elif alert == 'Red':
return [255, 0, 0, 160]
return [128, 128, 128, 160]
fault_df['color'] = fault_df['Alert Level'].apply(get_color)
# ---- Map ----
st.subheader("π Pole Locations with Selected Faults")
st.pydeck_chart(pdk.Deck(
initial_view_state=pdk.ViewState(
latitude=SITES[selected_site][0],
longitude=SITES[selected_site][1],
zoom=12,
pitch=50
),
layers=[
pdk.Layer(
'ScatterplotLayer',
data=fault_df,
get_position='[Longitude, Latitude]',
get_color='color',
get_radius=100,
pickable=True,
)
],
tooltip={
"html": """
<b>Pole ID:</b> {Pole ID}<br/>
<b>Alert Level:</b> {Alert Level}<br/>
<b>Health Score:</b> {Health Score}<br/>
<b>Power Status:</b> {Power Status}<br/>
<b>Vibration (g):</b> {Vibration (g)}<br/>
<b>Camera:</b> {Camera Status}<br/>
<b>Solar (kWh):</b> {Solar (kWh)}<br/>
<b>Wind (kWh):</b> {Wind (kWh)}<br/>
<b>Last Checked:</b> {Last Checked}
""",
"style": {
"backgroundColor": "steelblue",
"color": "white",
"fontSize": "12px"
}
}
))
|