nkellil commited on
Commit
7fa2dab
·
verified ·
1 Parent(s): 85d4768

undefined - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +894 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Drone1
3
- emoji: 🦀
4
- colorFrom: blue
5
- colorTo: purple
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: drone1
3
+ emoji: 🐳
4
+ colorFrom: red
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,894 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ThermoDrone - Photovoltaic Plant Monitoring</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCGNXE_QanVIz3XUFL0EDgYn2ZQ1QQhG1U&libraries=visualization,geometry&callback=initMap" async defer></script>
10
+ <style>
11
+ #map {
12
+ height: 100vh;
13
+ width: 100%;
14
+ }
15
+ .thermal-gradient {
16
+ background: linear-gradient(to right, #000000, #4000ff, #00ffff, #00ff00, #ffff00, #ff0000);
17
+ height: 20px;
18
+ border-radius: 4px;
19
+ }
20
+ .telemetry-value {
21
+ font-family: 'Courier New', monospace;
22
+ font-weight: bold;
23
+ }
24
+ .sidebar {
25
+ transition: all 0.3s ease;
26
+ }
27
+ .sidebar.collapsed {
28
+ width: 60px;
29
+ }
30
+ .sidebar.collapsed .sidebar-content {
31
+ opacity: 0;
32
+ pointer-events: none;
33
+ }
34
+ .defect-marker {
35
+ animation: pulse 2s infinite;
36
+ }
37
+ @keyframes pulse {
38
+ 0% { transform: scale(1); opacity: 0.7; }
39
+ 50% { transform: scale(1.2); opacity: 1; }
40
+ 100% { transform: scale(1); opacity: 0.7; }
41
+ }
42
+ #image-modal {
43
+ transition: opacity 0.3s ease;
44
+ }
45
+ .modal-content {
46
+ max-height: 90vh;
47
+ }
48
+ .active {
49
+ background-color: #3b82f6;
50
+ color: white;
51
+ }
52
+ </style>
53
+ </head>
54
+ <body class="bg-gray-100 h-screen flex overflow-hidden">
55
+ <!-- Sidebar -->
56
+ <div id="sidebar" class="sidebar bg-gray-800 text-white w-64 flex flex-col">
57
+ <div class="p-4 flex items-center justify-between border-b border-gray-700">
58
+ <div class="flex items-center space-x-2">
59
+ <i class="fas fa-drone-alt text-blue-400 text-2xl"></i>
60
+ <h1 class="text-xl font-bold">ThermoDrone</h1>
61
+ </div>
62
+ <button id="toggle-sidebar" class="text-gray-400 hover:text-white">
63
+ <i class="fas fa-chevron-left"></i>
64
+ </button>
65
+ </div>
66
+
67
+ <div class="sidebar-content flex-1 overflow-y-auto p-4 space-y-6">
68
+ <!-- Connection Panel -->
69
+ <div class="bg-gray-700 rounded-lg p-4">
70
+ <h2 class="text-lg font-semibold mb-3 flex items-center">
71
+ <i class="fas fa-plug mr-2 text-blue-400"></i>
72
+ Connection
73
+ </h2>
74
+ <div class="space-y-3">
75
+ <div>
76
+ <label class="block text-sm font-medium mb-1">Serial Port</label>
77
+ <select id="com-port" class="w-full bg-gray-600 border border-gray-500 rounded px-3 py-2 text-sm">
78
+ <option value="">Select COM Port</option>
79
+ <option value="COM3">COM3 (USB Serial Device)</option>
80
+ <option value="COM8">COM8 (FTDI Serial Port)</option>
81
+ </select>
82
+ </div>
83
+ <div>
84
+ <label class="block text-sm font-medium mb-1">Baud Rate</label>
85
+ <select id="baud-rate" class="w-full bg-gray-600 border border-gray-500 rounded px-3 py-2 text-sm">
86
+ <option value="57600">57600</option>
87
+ <option value="115200" selected>115200</option>
88
+ <option value="921600">921600</option>
89
+ </select>
90
+ </div>
91
+ <button id="connect-btn" class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 rounded flex items-center justify-center">
92
+ <i class="fas fa-link mr-2"></i> Connect
93
+ </button>
94
+ <button id="disconnect-btn" class="w-full bg-gray-600 hover:bg-gray-700 text-white py-2 rounded flex items-center justify-center hidden">
95
+ <i class="fas fa-unlink mr-2"></i> Disconnect
96
+ </button>
97
+ </div>
98
+ </div>
99
+
100
+ <!-- Mission Planning -->
101
+ <div class="bg-gray-700 rounded-lg p-4">
102
+ <h2 class="text-lg font-semibold mb-3 flex items-center">
103
+ <i class="fas fa-map-marked-alt mr-2 text-green-400"></i>
104
+ Mission Planning
105
+ </h2>
106
+ <div class="space-y-3">
107
+ <div class="flex space-x-2">
108
+ <button id="add-waypoint-btn" class="flex-1 bg-green-600 hover:bg-green-700 text-white py-2 rounded flex items-center justify-center text-sm">
109
+ <i class="fas fa-plus mr-1"></i> Add Waypoint
110
+ </button>
111
+ <button id="clear-waypoints-btn" class="flex-1 bg-red-600 hover:bg-red-700 text-white py-2 rounded flex items-center justify-center text-sm">
112
+ <i class="fas fa-trash mr-1"></i> Clear All
113
+ </button>
114
+ </div>
115
+ <div>
116
+ <label class="block text-sm font-medium mb-1">Altitude (m)</label>
117
+ <input type="number" id="waypoint-altitude" value="50" min="10" max="200" class="w-full bg-gray-600 border border-gray-500 rounded px-3 py-2 text-sm">
118
+ </div>
119
+ <div>
120
+ <label class="block text-sm font-medium mb-1">Speed (m/s)</label>
121
+ <input type="number" id="waypoint-speed" value="5" min="1" max="15" class="w-full bg-gray-600 border border-gray-500 rounded px-3 py-2 text-sm">
122
+ </div>
123
+ <button id="upload-mission-btn" class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 rounded flex items-center justify-center">
124
+ <i class="fas fa-upload mr-2"></i> Upload Mission
125
+ </button>
126
+ <button id="start-mission-btn" class="w-full bg-green-600 hover:bg-green-700 text-white py-2 rounded flex items-center justify-center hidden">
127
+ <i class="fas fa-play mr-2"></i> Start Mission
128
+ </button>
129
+ <button id="pause-mission-btn" class="w-full bg-yellow-600 hover:bg-yellow-700 text-white py-2 rounded flex items-center justify-center hidden">
130
+ <i class="fas fa-pause mr-2"></i> Pause Mission
131
+ </button>
132
+ </div>
133
+ </div>
134
+
135
+ <!-- Thermal Analysis -->
136
+ <div class="bg-gray-700 rounded-lg p-4">
137
+ <h2 class="text-lg font-semibold mb-3 flex items-center">
138
+ <i class="fas fa-thermometer-half mr-2 text-red-400"></i>
139
+ Thermal Analysis
140
+ </h2>
141
+ <div class="space-y-3">
142
+ <div class="thermal-gradient rounded-full mb-2"></div>
143
+ <div class="flex justify-between text-xs">
144
+ <span>20°C</span>
145
+ <span>40°C</span>
146
+ <span>60°C</span>
147
+ <span>80°C</span>
148
+ <span>100°C</span>
149
+ </div>
150
+ <div>
151
+ <label class="block text-sm font-medium mb-1">Threshold (°C)</label>
152
+ <input type="number" id="thermal-threshold" value="70" min="30" max="120" class="w-full bg-gray-600 border border-gray-500 rounded px-3 py-2 text-sm">
153
+ </div>
154
+ <div class="flex items-center">
155
+ <input type="checkbox" id="enable-yolo" class="mr-2" checked>
156
+ <label for="enable-yolo" class="text-sm">Enable Defect Detection</label>
157
+ </div>
158
+ <button id="analyze-btn" class="w-full bg-purple-600 hover:bg-purple-700 text-white py-2 rounded flex items-center justify-center">
159
+ <i class="fas fa-search mr-2"></i> Analyze Images
160
+ </button>
161
+ </div>
162
+ </div>
163
+ </div>
164
+
165
+ <div class="p-4 border-t border-gray-700">
166
+ <div class="text-xs text-gray-400">
167
+ <p>MAVLink Connected: <span id="mavlink-status" class="text-red-500">No</span></p>
168
+ <p>Drone Status: <span id="drone-status" class="text-gray-300">Disconnected</span></p>
169
+ </div>
170
+ </div>
171
+ </div>
172
+
173
+ <!-- Main Content -->
174
+ <div class="flex-1 flex flex-col overflow-hidden">
175
+ <!-- Top Bar -->
176
+ <div class="bg-gray-800 text-white p-3 flex items-center justify-between">
177
+ <div class="flex items-center space-x-4">
178
+ <button id="mobile-menu-btn" class="md:hidden text-gray-300 hover:text-white">
179
+ <i class="fas fa-bars"></i>
180
+ </button>
181
+ <h2 class="text-lg font-semibold">Photovoltaic Plant Monitoring</h2>
182
+ </div>
183
+ <div class="flex items-center space-x-4">
184
+ <div class="flex items-center space-x-2">
185
+ <i class="fas fa-battery-three-quarters text-green-400"></i>
186
+ <span id="battery-level" class="text-sm">--%</span>
187
+ </div>
188
+ <div class="flex items-center space-x-2">
189
+ <i class="fas fa-satellite-dish text-blue-400"></i>
190
+ <span id="satellites" class="text-sm">--</span>
191
+ </div>
192
+ <div class="flex items-center space-x-2">
193
+ <i class="fas fa-map-marker-alt text-yellow-400"></i>
194
+ <span id="gps-coords" class="text-sm">--, --</span>
195
+ </div>
196
+ </div>
197
+ </div>
198
+
199
+ <!-- Map and Telemetry Area -->
200
+ <div class="flex-1 flex flex-col md:flex-row overflow-hidden">
201
+ <!-- Map Container -->
202
+ <div class="flex-1 relative">
203
+ <div id="map" class="absolute inset-0"></div>
204
+
205
+ <!-- Map Controls -->
206
+ <div class="absolute top-4 right-4 space-y-2 z-10">
207
+ <button id="satellite-btn" class="bg-white p-2 rounded-full shadow hover:bg-gray-100" title="Satellite View">
208
+ <i class="fas fa-satellite text-gray-800"></i>
209
+ </button>
210
+ <button id="terrain-btn" class="bg-white p-2 rounded-full shadow hover:bg-gray-100" title="Terrain View">
211
+ <i class="fas fa-mountain text-gray-800"></i>
212
+ </button>
213
+ <button id="thermal-overlay-btn" class="bg-white p-2 rounded-full shadow hover:bg-gray-100" title="Thermal Overlay">
214
+ <i class="fas fa-fire text-gray-800"></i>
215
+ </button>
216
+ </div>
217
+
218
+ <!-- Mission Progress -->
219
+ <div class="absolute bottom-4 left-4 bg-white bg-opacity-90 p-3 rounded shadow z-10">
220
+ <h3 class="font-semibold text-sm mb-1">Mission Progress</h3>
221
+ <div class="w-full bg-gray-200 rounded-full h-2.5">
222
+ <div id="mission-progress" class="bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div>
223
+ </div>
224
+ <div class="flex justify-between text-xs mt-1">
225
+ <span>0%</span>
226
+ <span id="mission-percentage">0%</span>
227
+ </div>
228
+ </div>
229
+ </div>
230
+
231
+ <!-- Telemetry Panel -->
232
+ <div class="w-full md:w-64 bg-gray-700 text-white overflow-y-auto border-t md:border-t-0 md:border-l border-gray-600">
233
+ <div class="p-4 space-y-6">
234
+ <div>
235
+ <h3 class="font-semibold mb-2 flex items-center">
236
+ <i class="fas fa-heartbeat mr-2 text-red-400"></i>
237
+ Drone Telemetry
238
+ </h3>
239
+ <div class="space-y-2">
240
+ <div class="flex justify-between">
241
+ <span class="text-sm text-gray-300">Mode:</span>
242
+ <span id="flight-mode" class="telemetry-value">--</span>
243
+ </div>
244
+ <div class="flex justify-between">
245
+ <span class="text-sm text-gray-300">Altitude:</span>
246
+ <span id="altitude" class="telemetry-value">-- m</span>
247
+ </div>
248
+ <div class="flex justify-between">
249
+ <span class="text-sm text-gray-300">Speed:</span>
250
+ <span id="speed" class="telemetry-value">-- m/s</span>
251
+ </div>
252
+ <div class="flex justify-between">
253
+ <span class="text-sm text-gray-300">Heading:</span>
254
+ <span id="heading" class="telemetry-value">--°</span>
255
+ </div>
256
+ <div class="flex justify-between">
257
+ <span class="text-sm text-gray-300">Distance:</span>
258
+ <span id="distance" class="telemetry-value">-- m</span>
259
+ </div>
260
+ </div>
261
+ </div>
262
+
263
+ <div>
264
+ <h3 class="font-semibold mb-2 flex items-center">
265
+ <i class="fas fa-bolt mr-2 text-yellow-400"></i>
266
+ Power System
267
+ </h3>
268
+ <div class="space-y-2">
269
+ <div class="flex justify-between">
270
+ <span class="text-sm text-gray-300">Voltage:</span>
271
+ <span id="voltage" class="telemetry-value">-- V</span>
272
+ </div>
273
+ <div class="flex justify-between">
274
+ <span class="text-sm text-gray-300">Current:</span>
275
+ <span id="current" class="telemetry-value">-- A</span>
276
+ </div>
277
+ <div class="flex justify-between">
278
+ <span class="text-sm text-gray-300">Remaining:</span>
279
+ <span id="battery-remaining" class="telemetry-value">--%</span>
280
+ </div>
281
+ <div class="flex justify-between">
282
+ <span class="text-sm text-gray-300">Flight Time:</span>
283
+ <span id="flight-time" class="telemetry-value">--:--</span>
284
+ </div>
285
+ </div>
286
+ </div>
287
+
288
+ <div>
289
+ <h3 class="font-semibold mb-2 flex items-center">
290
+ <i class="fas fa-search mr-2 text-purple-400"></i>
291
+ Thermal Defects
292
+ </h3>
293
+ <div class="space-y-2">
294
+ <div class="flex justify-between">
295
+ <span class="text-sm text-gray-300">Detected:</span>
296
+ <span id="defects-count" class="telemetry-value">0</span>
297
+ </div>
298
+ <div class="flex justify-between">
299
+ <span class="text-sm text-gray-300">Max Temp:</span>
300
+ <span id="max-temp" class="telemetry-value">--°C</span>
301
+ </div>
302
+ <div class="flex justify-between">
303
+ <span class="text-sm text-gray-300">Avg Temp:</span>
304
+ <span id="avg-temp" class="telemetry-value">--°C</span>
305
+ </div>
306
+ </div>
307
+ </div>
308
+
309
+ <div class="bg-gray-600 rounded p-3">
310
+ <h3 class="font-semibold mb-2 text-sm">Quick Actions</h3>
311
+ <div class="grid grid-cols-2 gap-2">
312
+ <button id="rtl-btn" class="bg-yellow-600 hover:bg-yellow-700 text-white py-1 px-2 rounded text-xs">
313
+ <i class="fas fa-home mr-1"></i> RTL
314
+ </button>
315
+ <button id="loiter-btn" class="bg-blue-600 hover:bg-blue-700 text-white py-1 px-2 rounded text-xs">
316
+ <i class="fas fa-circle-notch mr-1"></i> Loiter
317
+ </button>
318
+ <button id="land-btn" class="bg-red-600 hover:bg-red-700 text-white py-1 px-2 rounded text-xs">
319
+ <i class="fas fa-arrow-down mr-1"></i> Land
320
+ </button>
321
+ <button id="takeoff-btn" class="bg-green-600 hover:bg-green-700 text-white py-1 px-2 rounded text-xs">
322
+ <i class="fas fa-arrow-up mr-1"></i> Takeoff
323
+ </button>
324
+ </div>
325
+ </div>
326
+ </div>
327
+ </div>
328
+ </div>
329
+ </div>
330
+
331
+ <!-- Image Preview Modal -->
332
+ <div id="image-modal" class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden">
333
+ <div class="bg-gray-800 rounded-lg max-w-4xl w-full modal-content overflow-hidden">
334
+ <div class="flex justify-between items-center p-4 border-b border-gray-700">
335
+ <h3 class="text-lg font-semibold">Thermal Image Analysis</h3>
336
+ <button id="close-modal" class="text-gray-400 hover:text-white">
337
+ <i class="fas fa-times"></i>
338
+ </button>
339
+ </div>
340
+ <div class="p-4 flex flex-col md:flex-row overflow-auto">
341
+ <div class="w-full md:w-2/3 mb-4 md:mb-0 md:pr-4">
342
+ <img id="modal-image" src="" alt="Thermal Image" class="w-full h-auto rounded max-h-[60vh] object-contain">
343
+ </div>
344
+ <div class="w-full md:w-1/3">
345
+ <h4 class="font-semibold mb-2">Defect Details</h4>
346
+ <div class="space-y-3">
347
+ <div>
348
+ <label class="block text-sm text-gray-300">Module ID:</label>
349
+ <p id="module-id" class="font-mono">PV-12-045</p>
350
+ </div>
351
+ <div>
352
+ <label class="block text-sm text-gray-300">Temperature:</label>
353
+ <p id="module-temp" class="font-mono">78.4°C</p>
354
+ </div>
355
+ <div>
356
+ <label class="block text-sm text-gray-300">Location:</label>
357
+ <p id="module-location" class="font-mono">Row 12, Position 45</p>
358
+ </div>
359
+ <div>
360
+ <label class="block text-sm text-gray-300">Defect Type:</label>
361
+ <p id="defect-type" class="font-mono">Hot Spot</p>
362
+ </div>
363
+ <div>
364
+ <label class="block text-sm text-gray-300">Confidence:</label>
365
+ <p id="defect-confidence" class="font-mono">92%</p>
366
+ </div>
367
+ </div>
368
+ <div class="mt-4">
369
+ <button class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 rounded">
370
+ <i class="fas fa-file-export mr-2"></i> Export Report
371
+ </button>
372
+ </div>
373
+ </div>
374
+ </div>
375
+ </div>
376
+ </div>
377
+
378
+ <script>
379
+ // Initialize Google Maps
380
+ let map;
381
+ let droneMarker;
382
+ let waypoints = [];
383
+ let defectMarkers = [];
384
+ let isConnected = false;
385
+ let missionWaypoints = [];
386
+ let currentWaypointIndex = 0;
387
+ let missionInterval;
388
+ let isMissionPaused = false;
389
+ let flightPath = null;
390
+
391
+ function initMap() {
392
+ try {
393
+ // Default to a solar farm location (example: Topaz Solar Farm, California)
394
+ const solarFarm = { lat: 36.6625, lng: 2.71986 };
395
+
396
+ map = new google.maps.Map(document.getElementById('map'), {
397
+ center: solarFarm,
398
+ zoom: 17,
399
+ mapTypeId: 'satellite',
400
+ disableDefaultUI: true,
401
+ mapTypeControlOptions: {
402
+ mapTypeIds: ['roadmap', 'satellite', 'hybrid', 'terrain']
403
+ }
404
+ });
405
+
406
+ // Add drone marker
407
+ droneMarker = new google.maps.Marker({
408
+ position: solarFarm,
409
+ map: map,
410
+ icon: {
411
+ path: google.maps.SymbolPath.CIRCLE,
412
+ fillColor: '#ef4444',
413
+ fillOpacity: 1,
414
+ strokeColor: 'white',
415
+ strokeWeight: 2,
416
+ scale: 10
417
+ },
418
+ title: 'Drone',
419
+ zIndex: 999
420
+ });
421
+
422
+ // Add click listener for waypoints
423
+ map.addListener('click', (event) => {
424
+ const addWaypointBtn = document.getElementById('add-waypoint-btn');
425
+ if (addWaypointBtn.classList.contains('active')) {
426
+ addWaypoint(event.latLng);
427
+ }
428
+ });
429
+
430
+ // Load saved waypoints from localStorage
431
+ loadWaypoints();
432
+
433
+ console.log("Map initialized successfully");
434
+
435
+ } catch (error) {
436
+ console.error("Error loading map:", error);
437
+ alert("Unable to load map. Please check your internet connection and API key.");
438
+ }
439
+ }
440
+
441
+ function addWaypoint(location) {
442
+ const waypointNumber = waypoints.length + 1;
443
+ const altitude = document.getElementById('waypoint-altitude').value;
444
+
445
+ const marker = new google.maps.Marker({
446
+ position: location,
447
+ map: map,
448
+ icon: {
449
+ path: google.maps.SymbolPath.CIRCLE,
450
+ fillColor: '#3b82f6',
451
+ fillOpacity: 1,
452
+ strokeColor: 'white',
453
+ strokeWeight: 2,
454
+ scale: 8
455
+ },
456
+ label: {
457
+ text: waypointNumber.toString(),
458
+ color: 'white',
459
+ fontSize: '10px'
460
+ },
461
+ title: `Waypoint ${waypointNumber} (${altitude}m)`
462
+ });
463
+
464
+ // Store additional waypoint data
465
+ marker.altitude = altitude;
466
+ marker.speed = document.getElementById('waypoint-speed').value;
467
+
468
+ waypoints.push(marker);
469
+ missionWaypoints.push(location);
470
+
471
+ // Draw flight path
472
+ drawFlightPath();
473
+
474
+ // Save waypoints to localStorage
475
+ saveWaypoints();
476
+ }
477
+
478
+ function drawFlightPath() {
479
+ // Clear previous path if exists
480
+ if (flightPath) {
481
+ flightPath.setMap(null);
482
+ }
483
+
484
+ if (waypoints.length > 1) {
485
+ flightPath = new google.maps.Polyline({
486
+ path: waypoints.map(wp => wp.getPosition()),
487
+ geodesic: true,
488
+ strokeColor: '#3b82f6',
489
+ strokeOpacity: 1.0,
490
+ strokeWeight: 3,
491
+ zIndex: 1
492
+ });
493
+
494
+ flightPath.setMap(map);
495
+ }
496
+ }
497
+
498
+ function clearWaypoints() {
499
+ waypoints.forEach(marker => marker.setMap(null));
500
+ waypoints = [];
501
+ missionWaypoints = [];
502
+
503
+ if (flightPath) {
504
+ flightPath.setMap(null);
505
+ flightPath = null;
506
+ }
507
+
508
+ document.getElementById('mission-percentage').textContent = '0%';
509
+ document.getElementById('mission-progress').style.width = '0%';
510
+ currentWaypointIndex = 0;
511
+
512
+ // Clear saved waypoints
513
+ localStorage.removeItem('savedWaypoints');
514
+ }
515
+
516
+ function saveWaypoints() {
517
+ const waypointsData = waypoints.map(marker => ({
518
+ lat: marker.getPosition().lat(),
519
+ lng: marker.getPosition().lng(),
520
+ altitude: marker.altitude,
521
+ speed: marker.speed
522
+ }));
523
+ localStorage.setItem('savedWaypoints', JSON.stringify(waypointsData));
524
+ }
525
+
526
+ function loadWaypoints() {
527
+ const savedWaypoints = localStorage.getItem('savedWaypoints');
528
+ if (savedWaypoints) {
529
+ const waypointsData = JSON.parse(savedWaypoints);
530
+ waypointsData.forEach(wpData => {
531
+ const location = new google.maps.LatLng(wpData.lat, wpData.lng);
532
+ document.getElementById('waypoint-altitude').value = wpData.altitude;
533
+ document.getElementById('waypoint-speed').value = wpData.speed;
534
+ addWaypoint(location);
535
+ });
536
+ }
537
+ }
538
+
539
+ function startMission() {
540
+ if (isMissionPaused) {
541
+ isMissionPaused = false;
542
+ simulateDroneMovement();
543
+ return;
544
+ }
545
+
546
+ if (missionWaypoints.length === 0) {
547
+ alert('Please add waypoints first');
548
+ return;
549
+ }
550
+
551
+ // Reset mission progress
552
+ currentWaypointIndex = 0;
553
+ document.getElementById('mission-percentage').textContent = '0%';
554
+ document.getElementById('mission-progress').style.width = '0%';
555
+
556
+ // Clear existing defects
557
+ defectMarkers.forEach(marker => marker.setMap(null));
558
+ defectMarkers = [];
559
+ document.getElementById('defects-count').textContent = '0';
560
+ document.getElementById('max-temp').textContent = '--°C';
561
+ document.getElementById('avg-temp').textContent = '--°C';
562
+
563
+ // Start simulation
564
+ simulateDroneMovement();
565
+ }
566
+
567
+ function pauseMission() {
568
+ isMissionPaused = true;
569
+ if (missionInterval) {
570
+ clearTimeout(missionInterval);
571
+ }
572
+ }
573
+
574
+ function simulateDroneMovement() {
575
+ if (isMissionPaused || missionWaypoints.length === 0) return;
576
+
577
+ const nextWaypoint = missionWaypoints[currentWaypointIndex];
578
+ const currentPosition = droneMarker.getPosition();
579
+
580
+ // Calculate new position 1% closer to the waypoint
581
+ const latDiff = nextWaypoint.lat() - currentPosition.lat();
582
+ const lngDiff = nextWaypoint.lng() - currentPosition.lng();
583
+
584
+ const newLat = currentPosition.lat() + latDiff * 0.01;
585
+ const newLng = currentPosition.lng() + lngDiff * 0.01;
586
+
587
+ const newPosition = new google.maps.LatLng(newLat, newLng);
588
+
589
+ // Calculate distance to waypoint
590
+ const distance = google.maps.geometry.spherical.computeDistanceBetween(
591
+ newPosition, nextWaypoint);
592
+
593
+ // Update drone position and heading
594
+ droneMarker.setPosition(newPosition);
595
+
596
+ // Calculate heading (bearing)
597
+ const heading = google.maps.geometry.spherical.computeHeading(
598
+ currentPosition, newPosition);
599
+ droneMarker.setIcon({
600
+ path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
601
+ fillColor: '#ef4444',
602
+ fillOpacity: 1,
603
+ strokeColor: 'white',
604
+ strokeWeight: 1,
605
+ scale: 5,
606
+ rotation: heading
607
+ });
608
+
609
+ // Update telemetry
610
+ updateTelemetry(newPosition, heading, distance);
611
+
612
+ // Check if reached waypoint
613
+ if (distance < 5) { // 5 meters threshold
614
+ currentWaypointIndex = (currentWaypointIndex + 1) % missionWaypoints.length;
615
+
616
+ // Update mission progress
617
+ const progress = Math.floor((currentWaypointIndex / missionWaypoints.length) * 100);
618
+ document.getElementById('mission-percentage').textContent = `${progress}%`;
619
+ document.getElementById('mission-progress').style.width = `${progress}%`;
620
+
621
+ // If completed full loop, pause mission
622
+ if (currentWaypointIndex === 0) {
623
+ pauseMission();
624
+ document.getElementById('start-mission-btn').classList.remove('hidden');
625
+ document.getElementById('pause-mission-btn').classList.add('hidden');
626
+ return;
627
+ }
628
+ }
629
+
630
+ // Randomly detect thermal defects during flight
631
+ if (Math.random() < 0.02 && document.getElementById('enable-yolo').checked) {
632
+ detectThermalDefect(newPosition);
633
+ }
634
+
635
+ // Continue simulation
636
+ missionInterval = setTimeout(simulateDroneMovement, 100);
637
+ }
638
+
639
+ function updateTelemetry(position, heading, distance) {
640
+ document.getElementById('gps-coords').textContent =
641
+ `${position.lat().toFixed(6)}, ${position.lng().toFixed(6)}`;
642
+ document.getElementById('altitude').textContent = `${waypoints[currentWaypointIndex]?.altitude || '50'} m`;
643
+ document.getElementById('speed').textContent = `${waypoints[currentWaypointIndex]?.speed || '5'} m/s`;
644
+ document.getElementById('heading').textContent = `${Math.round(heading)}°`;
645
+ document.getElementById('distance').textContent = `${Math.round(distance)} m`;
646
+
647
+ const batteryLevel = Math.floor(80 - (currentWaypointIndex / missionWaypoints.length) * 30);
648
+ document.getElementById('battery-level').textContent = `${batteryLevel}%`;
649
+ document.getElementById('battery-remaining').textContent = `${batteryLevel}%`;
650
+
651
+ document.getElementById('satellites').textContent = '12';
652
+ document.getElementById('flight-mode').textContent = 'AUTO';
653
+ document.getElementById('voltage').textContent = '15.7 V';
654
+ document.getElementById('current').textContent = '12.3 A';
655
+
656
+ // Update flight time (simulated)
657
+ const minutes = Math.floor(currentWaypointIndex / 10);
658
+ const seconds = currentWaypointIndex % 10 * 6;
659
+ document.getElementById('flight-time').textContent =
660
+ `${minutes}:${seconds < 10 ? '0' + seconds : seconds}`;
661
+ }
662
+
663
+ function detectThermalDefect(position) {
664
+ // Random offset to place defect marker near drone
665
+ const latOffset = (Math.random() - 0.5) * 0.0005;
666
+ const lngOffset = (Math.random() - 0.5) * 0.0005;
667
+
668
+ const defectLocation = new google.maps.LatLng(
669
+ position.lat() + latOffset,
670
+ position.lng() + lngOffset
671
+ );
672
+
673
+ const temp = Math.round(70 + Math.random() * 30);
674
+ const defectTypes = ['Hot Spot', 'Broken Cell', 'Bypass Diode Failure', 'Soiling'];
675
+ const defectType = defectTypes[Math.floor(Math.random() * defectTypes.length)];
676
+
677
+ const marker = new google.maps.Marker({
678
+ position: defectLocation,
679
+ map: map,
680
+ icon: {
681
+ path: google.maps.SymbolPath.CIRCLE,
682
+ fillColor: 'rgba(239, 68, 68, 0.7)',
683
+ fillOpacity: 1,
684
+ strokeColor: 'white',
685
+ strokeWeight: 1,
686
+ scale: 8
687
+ },
688
+ title: `Thermal Defect: ${temp}°C (${defectType})`,
689
+ zIndex: 10
690
+ });
691
+
692
+ // Add animation class
693
+ marker.addListener('domready', () => {
694
+ const markerElement = document.querySelector(`[title="Thermal Defect: ${temp}°C (${defectType})"]`);
695
+ if (markerElement) {
696
+ markerElement.classList.add('defect-marker');
697
+ }
698
+ });
699
+
700
+ defectMarkers.push(marker);
701
+
702
+ // Add click listener to show defect details
703
+ marker.addListener('click', () => {
704
+ showDefectDetails(defectLocation, temp, defectType);
705
+ });
706
+
707
+ // Update defects count
708
+ document.getElementById('defects-count').textContent = defectMarkers.length;
709
+
710
+ // Update max and avg temp
711
+ const temps = defectMarkers.map(m => parseInt(m.getTitle().match(/(\d+)°C/)[1]));
712
+ const maxTemp = Math.max(...temps);
713
+ const avgTemp = Math.round(temps.reduce((a, b) => a + b, 0) / temps.length);
714
+
715
+ document.getElementById('max-temp').textContent = `${maxTemp}°C`;
716
+ document.getElementById('avg-temp').textContent = `${avgTemp}°C`;
717
+ }
718
+
719
+ function showDefectDetails(location, temperature, defectType) {
720
+ document.getElementById('modal-image').src = 'https://via.placeholder.com/800x600/333/fff?text=Thermal+Image+Analysis';
721
+ document.getElementById('module-temp').textContent = `${temperature}°C`;
722
+ document.getElementById('defect-type').textContent = defectType;
723
+ document.getElementById('defect-confidence').textContent = `${Math.round(85 + Math.random() * 15)}%`;
724
+
725
+ // Generate random module ID
726
+ const row = Math.floor(1 + Math.random() * 20);
727
+ const pos = Math.floor(1 + Math.random() * 100);
728
+ document.getElementById('module-id').textContent = `PV-${row}-${pos}`;
729
+ document.getElementById('module-location').textContent = `Row ${row}, Position ${pos}`;
730
+
731
+ // Show modal
732
+ document.getElementById('image-modal').classList.remove('hidden');
733
+ }
734
+
735
+ // DOM Event Listeners
736
+ document.addEventListener('DOMContentLoaded', () => {
737
+ // Initialize map when window loads
738
+ window.initMap = initMap;
739
+
740
+ // Toggle sidebar
741
+ document.getElementById('toggle-sidebar').addEventListener('click', () => {
742
+ document.getElementById('sidebar').classList.toggle('collapsed');
743
+ const icon = document.querySelector('#toggle-sidebar i');
744
+ if (document.getElementById('sidebar').classList.contains('collapsed')) {
745
+ icon.classList.remove('fa-chevron-left');
746
+ icon.classList.add('fa-chevron-right');
747
+ } else {
748
+ icon.classList.remove('fa-chevron-right');
749
+ icon.classList.add('fa-chevron-left');
750
+ }
751
+ });
752
+
753
+ // Mobile menu toggle
754
+ document.getElementById('mobile-menu-btn').addEventListener('click', () => {
755
+ document.getElementById('sidebar').classList.toggle('hidden');
756
+ });
757
+
758
+ // Connect button
759
+ document.getElementById('connect-btn').addEventListener('click', () => {
760
+ const comPort = document.getElementById('com-port').value;
761
+ const baudRate = document.getElementById('baud-rate').value;
762
+
763
+ if (!comPort) {
764
+ alert('Please select a COM port');
765
+ return;
766
+ }
767
+
768
+ // Simulate connection
769
+ isConnected = true;
770
+ document.getElementById('connect-btn').classList.add('hidden');
771
+ document.getElementById('disconnect-btn').classList.remove('hidden');
772
+ document.getElementById('mavlink-status').textContent = 'Yes';
773
+ document.getElementById('mavlink-status').classList.remove('text-red-500');
774
+ document.getElementById('mavlink-status').classList.add('text-green-500');
775
+ document.getElementById('drone-status').textContent = 'Connected';
776
+ document.getElementById('drone-status').classList.remove('text-gray-300');
777
+ document.getElementById('drone-status').classList.add('text-green-400');
778
+ document.getElementById('start-mission-btn').classList.remove('hidden');
779
+
780
+ // Simulate COM port connection
781
+ console.log(`Connected to ${comPort} at ${baudRate} baud`);
782
+ });
783
+
784
+ // Disconnect button
785
+ document.getElementById('disconnect-btn').addEventListener('click', () => {
786
+ isConnected = false;
787
+ document.getElementById('connect-btn').classList.remove('hidden');
788
+ document.getElementById('disconnect-btn').classList.add('hidden');
789
+ document.getElementById('mavlink-status').textContent = 'No';
790
+ document.getElementById('mavlink-status').classList.remove('text-green-500');
791
+ document.getElementById('mavlink-status').classList.add('text-red-500');
792
+ document.getElementById('drone-status').textContent = 'Disconnected';
793
+ document.getElementById('drone-status').classList.remove('text-green-400');
794
+ document.getElementById('drone-status').classList.add('text-gray-300');
795
+ document.getElementById('start-mission-btn').classList.add('hidden');
796
+ document.getElementById('pause-mission-btn').classList.add('hidden');
797
+
798
+ // Stop any ongoing mission
799
+ pauseMission();
800
+ });
801
+
802
+ // Add waypoint button
803
+ document.getElementById('add-waypoint-btn').addEventListener('click', function() {
804
+ this.classList.toggle('active');
805
+ if (this.classList.contains('active')) {
806
+ this.innerHTML = '<i class="fas fa-times mr-1"></i> Cancel';
807
+ document.getElementById('map').style.cursor = 'crosshair';
808
+ } else {
809
+ this.innerHTML = '<i class="fas fa-plus mr-1"></i> Add Waypoint';
810
+ document.getElementById('map').style.cursor = '';
811
+ }
812
+ });
813
+
814
+ // Clear waypoints button
815
+ document.getElementById('clear-waypoints-btn').addEventListener('click', clearWaypoints);
816
+
817
+ // Start mission button
818
+ document.getElementById('start-mission-btn').addEventListener('click', () => {
819
+ document.getElementById('start-mission-btn').classList.add('hidden');
820
+ document.getElementById('pause-mission-btn').classList.remove('hidden');
821
+ startMission();
822
+ });
823
+
824
+ // Pause mission button
825
+ document.getElementById('pause-mission-btn').addEventListener('click', () => {
826
+ document.getElementById('start-mission-btn').classList.remove('hidden');
827
+ document.getElementById('pause-mission-btn').classList.add('hidden');
828
+ pauseMission();
829
+ });
830
+
831
+ // Upload mission button
832
+ document.getElementById('upload-mission-btn').addEventListener('click', () => {
833
+ if (waypoints.length === 0) {
834
+ alert('Please add waypoints first');
835
+ return;
836
+ }
837
+
838
+ alert(`Mission with ${waypoints.length} waypoints uploaded to drone`);
839
+ });
840
+
841
+ // Analyze images button
842
+ document.getElementById('analyze-btn').addEventListener('click', () => {
843
+ const threshold = document.getElementById('thermal-threshold').value;
844
+ alert(`Analyzing thermal images with threshold ${threshold}°C`);
845
+ });
846
+
847
+ // Map type buttons
848
+ document.getElementById('satellite-btn').addEventListener('click', () => {
849
+ map.setMapTypeId('satellite');
850
+ });
851
+
852
+ document.getElementById('terrain-btn').addEventListener('click', () => {
853
+ map.setMapTypeId('terrain');
854
+ });
855
+
856
+ document.getElementById('thermal-overlay-btn').addEventListener('click', () => {
857
+ alert('Thermal overlay would be displayed here');
858
+ });
859
+
860
+ // Quick action buttons
861
+ document.getElementById('rtl-btn').addEventListener('click', () => {
862
+ pauseMission();
863
+ alert('Return to Launch command sent');
864
+ });
865
+
866
+ document.getElementById('loiter-btn').addEventListener('click', () => {
867
+ pauseMission();
868
+ alert('Loiter command sent');
869
+ });
870
+
871
+ document.getElementById('land-btn').addEventListener('click', () => {
872
+ pauseMission();
873
+ alert('Land command sent');
874
+ });
875
+
876
+ document.getElementById('takeoff-btn').addEventListener('click', () => {
877
+ alert('Takeoff command sent');
878
+ });
879
+
880
+ // Close modal button
881
+ document.getElementById('close-modal').addEventListener('click', () => {
882
+ document.getElementById('image-modal').classList.add('hidden');
883
+ });
884
+
885
+ // Handle clicks outside modal to close it
886
+ document.getElementById('image-modal').addEventListener('click', (e) => {
887
+ if (e.target === document.getElementById('image-modal')) {
888
+ document.getElementById('image-modal').classList.add('hidden');
889
+ }
890
+ });
891
+ });
892
+ </script>
893
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=nkellil/drone1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
894
+ </html>