Tigernawin commited on
Commit
aa9c18c
Β·
verified Β·
1 Parent(s): 6dd9ac0

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -0
app.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import pandas as pd
3
+ import streamlit as st
4
+ import pydeck as pdk
5
+ from datetime import datetime, timedelta
6
+ import math
7
+
8
+ # ---- Constants ----
9
+ POLES_PER_SITE = 12
10
+ SITES = {
11
+ "Hyderabad": [17.329181, 78.610091],
12
+ "Gadwal": [16.242267, 77.802164],
13
+ "Kurnool": [15.816862, 78.056204],
14
+ "Ballari": [15.159301, 76.908508]
15
+ }
16
+ ALERT_LEVELS = ["Green", "Yellow", "Red"]
17
+ DISTANCE_BETWEEN_POLES_METERS = 3.048 # 10 feet in meters
18
+
19
+ # ---- Helper Functions ----
20
+ def generate_grid_locations(base_lat, base_lon, count):
21
+ poles = []
22
+ spacing_deg_lat = DISTANCE_BETWEEN_POLES_METERS / 111320 # 1 deg lat ~ 111.32 km
23
+ spacing_deg_lon = DISTANCE_BETWEEN_POLES_METERS / (40075000 * math.cos(math.radians(base_lat)) / 360) # adjust for longitude distance
24
+ grid_size = int(math.ceil(math.sqrt(count)))
25
+ for i in range(count):
26
+ row = i // grid_size
27
+ col = i % grid_size
28
+ lat = base_lat + (row * spacing_deg_lat)
29
+ lon = base_lon + (col * spacing_deg_lon)
30
+ poles.append((lat, lon))
31
+ return poles
32
+
33
+ def simulate_pole(pole_id, site_name, lat, lon):
34
+ solar_kwh = round(random.uniform(3.0, 7.5), 2)
35
+ wind_kwh = round(random.uniform(0.5, 2.0), 2)
36
+ power_required = round(random.uniform(4.0, 8.0), 2)
37
+ total_power = solar_kwh + wind_kwh
38
+ power_status = 'Sufficient' if total_power >= power_required else 'Insufficient'
39
+
40
+ tilt_angle = round(random.uniform(0, 45), 2)
41
+ vibration = round(random.uniform(0, 5), 2)
42
+ camera_status = random.choice(['Online', 'Offline'])
43
+
44
+ alert_level = 'Green'
45
+ if tilt_angle > 30 or vibration > 3:
46
+ alert_level = 'Yellow'
47
+ if tilt_angle > 40 or vibration > 4.5:
48
+ alert_level = 'Red'
49
+
50
+ health_score = max(0, 100 - (tilt_angle + vibration * 10))
51
+ timestamp = datetime.now() - timedelta(hours=random.randint(0, 6))
52
+
53
+ return {
54
+ 'Pole ID': f'{site_name[:3].upper()}-{pole_id:03}',
55
+ 'Site': site_name,
56
+ 'Latitude': lat,
57
+ 'Longitude': lon,
58
+ 'Solar (kWh)': solar_kwh,
59
+ 'Wind (kWh)': wind_kwh,
60
+ 'Power Required (kWh)': power_required,
61
+ 'Total Power (kWh)': total_power,
62
+ 'Power Status': power_status,
63
+ 'Tilt Angle (Β°)': tilt_angle,
64
+ 'Vibration (g)': vibration,
65
+ 'Camera Status': camera_status,
66
+ 'Health Score': round(health_score, 2),
67
+ 'Alert Level': alert_level,
68
+ 'Last Checked': timestamp.strftime('%Y-%m-%d %H:%M:%S')
69
+ }
70
+
71
+ # ---- Streamlit UI ----
72
+ st.set_page_config(page_title="Smart Pole Monitoring", layout="wide")
73
+ st.title("🌍 Smart Renewable Pole Monitoring - Multi-Site")
74
+
75
+ # Simulate data across all sites
76
+ all_poles = []
77
+ for site_name, (base_lat, base_lon) in SITES.items():
78
+ locations = generate_grid_locations(base_lat, base_lon, POLES_PER_SITE)
79
+ for idx, (lat, lon) in enumerate(locations):
80
+ all_poles.append(simulate_pole(idx + 1, site_name, lat, lon))
81
+
82
+ df = pd.DataFrame(all_poles)
83
+
84
+ # Site buttons
85
+ st.subheader("πŸ“ Select Site")
86
+ selected_site = st.columns(len(SITES))
87
+ selected_site_name = None
88
+ for i, site in enumerate(SITES.keys()):
89
+ if selected_site[i].button(site):
90
+ selected_site_name = site
91
+
92
+ if not selected_site_name:
93
+ selected_site_name = list(SITES.keys())[0] # Default to first site
94
+
95
+ # Filter by Alert Level (Green, Yellow, Red)
96
+ st.subheader("🚦 Alert Level Filters")
97
+ col_g, col_y, col_r = st.columns(3)
98
+ show_green = col_g.checkbox("Green", True)
99
+ show_yellow = col_y.checkbox("Yellow", True)
100
+ show_red = col_r.checkbox("Red", True)
101
+
102
+ alert_filter = []
103
+ if show_green: alert_filter.append("Green")
104
+ if show_yellow: alert_filter.append("Yellow")
105
+ if show_red: alert_filter.append("Red")
106
+
107
+ site_df = df[(df['Site'] == selected_site_name) & (df['Alert Level'].isin(alert_filter))]
108
+
109
+ # Summary Metrics
110
+ col1, col2, col3 = st.columns(3)
111
+ col1.metric("Total Poles", site_df.shape[0])
112
+ col2.metric("Red Alerts", site_df[site_df['Alert Level'] == 'Red'].shape[0])
113
+ col3.metric("Power Insufficiencies", site_df[site_df['Power Status'] == 'Insufficient'].shape[0])
114
+
115
+ # Table View
116
+ st.subheader(f"πŸ“‹ Pole Data Table for {selected_site_name} - Alerts: {', '.join(alert_filter)}")
117
+ st.dataframe(site_df, use_container_width=True)
118
+
119
+ # Charts
120
+ st.subheader("πŸ“Š Energy Generation Comparison")
121
+ st.bar_chart(site_df[['Solar (kWh)', 'Wind (kWh)']].mean())
122
+
123
+ st.subheader("πŸ“ˆ Tilt vs. Vibration")
124
+ st.scatter_chart(site_df[['Tilt Angle (Β°)', 'Vibration (g)']])
125
+
126
+ # Map showing all alerts across all sites
127
+ st.subheader("πŸ“ Map of All Alert Pole Locations")
128
+ alert_df = df[df['Alert Level'].isin(alert_filter)]
129
+ if not alert_df.empty:
130
+ def get_color(row):
131
+ return {
132
+ 'Green': [0, 255, 0, 160],
133
+ 'Yellow': [255, 255, 0, 160],
134
+ 'Red': [255, 0, 0, 160]
135
+ }[row['Alert Level']]
136
+
137
+ alert_df['color'] = alert_df.apply(get_color, axis=1)
138
+
139
+ st.pydeck_chart(pdk.Deck(
140
+ initial_view_state=pdk.ViewState(
141
+ latitude=16.5,
142
+ longitude=77.5,
143
+ zoom=6,
144
+ pitch=45
145
+ ),
146
+ layers=[
147
+ pdk.Layer(
148
+ 'ScatterplotLayer',
149
+ data=alert_df,
150
+ get_position='[Longitude, Latitude]',
151
+ get_color='color',
152
+ get_radius=100,
153
+ pickable=True
154
+ )
155
+ ],
156
+ tooltip={"text": "Site: {Site}\nPole ID: {Pole ID}\nAlert: {Alert Level}"}
157
+ ))
158
+ else:
159
+ st.info("No alerts for the selected levels across all sites.")