privateuserh commited on
Commit
cc30b94
·
verified ·
1 Parent(s): 925cab7

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +735 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Privdrone
3
- emoji: 📚
4
- colorFrom: indigo
5
- colorTo: indigo
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: privdrone
3
+ emoji: 🐳
4
+ colorFrom: gray
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,735 @@
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>PicoDrone - BLE Drone Controller</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
+ <style>
10
+ .joystick {
11
+ width: 120px;
12
+ height: 120px;
13
+ background: rgba(255, 255, 255, 0.2);
14
+ border-radius: 50%;
15
+ position: relative;
16
+ touch-action: none;
17
+ }
18
+ .joystick-knob {
19
+ width: 50px;
20
+ height: 50px;
21
+ background: rgba(255, 255, 255, 0.8);
22
+ border-radius: 50%;
23
+ position: absolute;
24
+ top: 50%;
25
+ left: 50%;
26
+ transform: translate(-50%, -50%);
27
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
28
+ }
29
+ .battery-level {
30
+ height: 20px;
31
+ border-radius: 10px;
32
+ transition: width 0.3s ease;
33
+ }
34
+ .connection-pulse {
35
+ animation: pulse 2s infinite;
36
+ }
37
+ @keyframes pulse {
38
+ 0% { opacity: 1; }
39
+ 50% { opacity: 0.5; }
40
+ 100% { opacity: 1; }
41
+ }
42
+ .gauge {
43
+ width: 100%;
44
+ height: 10px;
45
+ border-radius: 5px;
46
+ overflow: hidden;
47
+ }
48
+ .gauge-fill {
49
+ height: 100%;
50
+ transition: width 0.3s ease;
51
+ }
52
+ </style>
53
+ </head>
54
+ <body class="bg-gray-900 text-white min-h-screen">
55
+ <div class="container mx-auto px-4 py-8 max-w-md">
56
+ <!-- Header -->
57
+ <header class="flex justify-between items-center mb-8">
58
+ <div>
59
+ <h1 class="text-2xl font-bold">PicoDrone</h1>
60
+ <p class="text-gray-400 text-sm">BLE Drone Controller</p>
61
+ </div>
62
+ <div class="flex items-center space-x-2">
63
+ <div id="connectionStatus" class="w-3 h-3 rounded-full bg-red-500"></div>
64
+ <span id="connectionText" class="text-sm">Disconnected</span>
65
+ </div>
66
+ </header>
67
+
68
+ <!-- Connection Panel -->
69
+ <div class="bg-gray-800 rounded-xl p-6 mb-6 shadow-lg">
70
+ <h2 class="text-lg font-semibold mb-4 flex items-center">
71
+ <i class="fas fa-bluetooth-b mr-2"></i> BLE Connection
72
+ </h2>
73
+
74
+ <div class="mb-4">
75
+ <label class="block text-sm font-medium mb-2">Select Device</label>
76
+ <div class="flex">
77
+ <select id="deviceList" class="bg-gray-700 text-white rounded-l-lg p-2 flex-grow focus:outline-none">
78
+ <option value="">No devices found</option>
79
+ </select>
80
+ <button id="refreshBtn" class="bg-blue-600 hover:bg-blue-700 px-4 rounded-r-lg">
81
+ <i class="fas fa-sync-alt"></i>
82
+ </button>
83
+ </div>
84
+ </div>
85
+
86
+ <button id="connectBtn" class="w-full py-3 bg-green-600 hover:bg-green-700 rounded-lg font-medium flex items-center justify-center">
87
+ <i class="fas fa-plug mr-2"></i> Connect to Drone
88
+ </button>
89
+ </div>
90
+
91
+ <!-- Status Panel -->
92
+ <div class="bg-gray-800 rounded-xl p-6 mb-6 shadow-lg">
93
+ <h2 class="text-lg font-semibold mb-4 flex items-center">
94
+ <i class="fas fa-info-circle mr-2"></i> Drone Status
95
+ </h2>
96
+
97
+ <div class="grid grid-cols-2 gap-4 mb-4">
98
+ <div>
99
+ <p class="text-sm text-gray-400">Battery</p>
100
+ <div class="flex items-center">
101
+ <div class="gauge bg-gray-700 mr-2">
102
+ <div id="batteryLevel" class="gauge-fill bg-green-500" style="width: 75%"></div>
103
+ </div>
104
+ <span id="batteryPercent">75%</span>
105
+ </div>
106
+ </div>
107
+ <div>
108
+ <p class="text-sm text-gray-400">Signal Strength</p>
109
+ <div class="flex items-center">
110
+ <div class="gauge bg-gray-700 mr-2">
111
+ <div id="signalLevel" class="gauge-fill bg-blue-500" style="width: 90%"></div>
112
+ </div>
113
+ <span id="signalPercent">-</span>
114
+ </div>
115
+ </div>
116
+ </div>
117
+
118
+ <div class="grid grid-cols-3 gap-2 text-center">
119
+ <div class="bg-gray-700 p-2 rounded-lg">
120
+ <p class="text-sm text-gray-400">Altitude</p>
121
+ <p id="altitudeValue" class="font-medium">0.0 m</p>
122
+ </div>
123
+ <div class="bg-gray-700 p-2 rounded-lg">
124
+ <p class="text-sm text-gray-400">Speed</p>
125
+ <p id="speedValue" class="font-medium">0.0 m/s</p>
126
+ </div>
127
+ <div class="bg-gray-700 p-2 rounded-lg">
128
+ <p class="text-sm text-gray-400">Flight Time</p>
129
+ <p id="flightTime" class="font-medium">00:00</p>
130
+ </div>
131
+ </div>
132
+ </div>
133
+
134
+ <!-- Flight Controls -->
135
+ <div class="bg-gray-800 rounded-xl p-6 shadow-lg">
136
+ <h2 class="text-lg font-semibold mb-6 flex items-center">
137
+ <i class="fas fa-gamepad mr-2"></i> Flight Controls
138
+ </h2>
139
+
140
+ <div class="flex justify-between items-center mb-8">
141
+ <!-- Left Joystick (Throttle/Yaw) -->
142
+ <div class="text-center">
143
+ <p class="text-sm mb-2">Throttle/Yaw</p>
144
+ <div id="leftJoystick" class="joystick mx-auto">
145
+ <div class="joystick-knob"></div>
146
+ </div>
147
+ </div>
148
+
149
+ <!-- Right Joystick (Pitch/Roll) -->
150
+ <div class="text-center">
151
+ <p class="text-sm mb-2">Pitch/Roll</p>
152
+ <div id="rightJoystick" class="joystick mx-auto">
153
+ <div class="joystick-knob"></div>
154
+ </div>
155
+ </div>
156
+ </div>
157
+
158
+ <!-- Action Buttons -->
159
+ <div class="grid grid-cols-3 gap-3 mb-4">
160
+ <button id="takeoffBtn" class="bg-green-600 hover:bg-green-700 py-3 rounded-lg font-medium disabled:opacity-50" disabled>
161
+ <i class="fas fa-rocket"></i> Takeoff
162
+ </button>
163
+ <button id="landBtn" class="bg-yellow-600 hover:bg-yellow-700 py-3 rounded-lg font-medium disabled:opacity-50" disabled>
164
+ <i class="fas fa-landmark"></i> Land
165
+ </button>
166
+ <button id="emergencyBtn" class="bg-red-600 hover:bg-red-700 py-3 rounded-lg font-medium disabled:opacity-50" disabled>
167
+ <i class="fas fa-exclamation-triangle"></i> Stop
168
+ </button>
169
+ </div>
170
+
171
+ <!-- Trim Controls -->
172
+ <div class="bg-gray-700 rounded-lg p-3 mb-4">
173
+ <p class="text-sm mb-2 text-center">Trim Adjustments</p>
174
+ <div class="grid grid-cols-4 gap-2">
175
+ <button class="trim-btn bg-gray-600 hover:bg-gray-500 p-2 rounded" data-axis="pitch" data-direction="up">
176
+ <i class="fas fa-arrow-up"></i> Pitch
177
+ </button>
178
+ <button class="trim-btn bg-gray-600 hover:bg-gray-500 p-2 rounded" data-axis="roll" data-direction="left">
179
+ <i class="fas fa-arrow-left"></i> Roll
180
+ </button>
181
+ <button class="trim-btn bg-gray-600 hover:bg-gray-500 p-2 rounded" data-axis="roll" data-direction="right">
182
+ <i class="fas fa-arrow-right"></i> Roll
183
+ </button>
184
+ <button class="trim-btn bg-gray-600 hover:bg-gray-500 p-2 rounded" data-axis="pitch" data-direction="down">
185
+ <i class="fas fa-arrow-down"></i> Pitch
186
+ </button>
187
+ </div>
188
+ </div>
189
+
190
+ <!-- Flight Mode Selector -->
191
+ <div class="mb-4">
192
+ <label class="block text-sm font-medium mb-2">Flight Mode</label>
193
+ <select id="flightMode" class="w-full bg-gray-700 text-white rounded-lg p-2 focus:outline-none">
194
+ <option value="beginner">Beginner (Limited)</option>
195
+ <option value="normal" selected>Normal</option>
196
+ <option value="acrobatic">Acrobatic</option>
197
+ </select>
198
+ </div>
199
+ </div>
200
+
201
+ <!-- Console Log -->
202
+ <div class="bg-gray-800 rounded-xl p-4 mt-6 shadow-lg">
203
+ <div class="flex justify-between items-center mb-2">
204
+ <h3 class="text-sm font-semibold">
205
+ <i class="fas fa-terminal mr-1"></i> Console
206
+ </h3>
207
+ <button id="clearConsole" class="text-xs text-gray-400 hover:text-white">
208
+ <i class="fas fa-trash-alt mr-1"></i> Clear
209
+ </button>
210
+ </div>
211
+ <div id="consoleOutput" class="bg-black text-green-400 font-mono text-xs p-2 rounded h-24 overflow-y-auto">
212
+ > Welcome to PicoDrone controller<br>
213
+ > Ready to connect...
214
+ </div>
215
+ </div>
216
+ </div>
217
+
218
+ <script>
219
+ // Simulated BLE functionality for demonstration
220
+ document.addEventListener('DOMContentLoaded', function() {
221
+ // UI Elements
222
+ const connectBtn = document.getElementById('connectBtn');
223
+ const refreshBtn = document.getElementById('refreshBtn');
224
+ const deviceList = document.getElementById('deviceList');
225
+ const connectionStatus = document.getElementById('connectionStatus');
226
+ const connectionText = document.getElementById('connectionText');
227
+ const takeoffBtn = document.getElementById('takeoffBtn');
228
+ const landBtn = document.getElementById('landBtn');
229
+ const emergencyBtn = document.getElementById('emergencyBtn');
230
+ const consoleOutput = document.getElementById('consoleOutput');
231
+ const clearConsole = document.getElementById('clearConsole');
232
+
233
+ // Status elements
234
+ const batteryLevel = document.getElementById('batteryLevel');
235
+ const batteryPercent = document.getElementById('batteryPercent');
236
+ const signalLevel = document.getElementById('signalLevel');
237
+ const signalPercent = document.getElementById('signalPercent');
238
+ const altitudeValue = document.getElementById('altitudeValue');
239
+ const speedValue = document.getElementById('speedValue');
240
+ const flightTime = document.getElementById('flightTime');
241
+
242
+ // Joystick elements
243
+ const leftJoystick = document.getElementById('leftJoystick');
244
+ const rightJoystick = document.getElementById('rightJoystick');
245
+ const leftKnob = leftJoystick.querySelector('.joystick-knob');
246
+ const rightKnob = rightJoystick.querySelector('.joystick-knob');
247
+
248
+ // Flight mode selector
249
+ const flightMode = document.getElementById('flightMode');
250
+
251
+ // Simulated devices
252
+ const devices = [
253
+ { name: 'PicoDrone-1', id: 'pico-1234' },
254
+ { name: 'PicoDrone-2', id: 'pico-5678' },
255
+ { name: 'PicoDrone-Test', id: 'pico-9ABC' }
256
+ ];
257
+
258
+ // State variables
259
+ let isConnected = false;
260
+ let isFlying = false;
261
+ let flightStartTime = null;
262
+ let flightTimer = null;
263
+ let batterySimulator = null;
264
+
265
+ // Initialize the app
266
+ function init() {
267
+ populateDeviceList();
268
+ setupEventListeners();
269
+ setupJoysticks();
270
+ }
271
+
272
+ // Populate device list with simulated devices
273
+ function populateDeviceList() {
274
+ deviceList.innerHTML = '';
275
+
276
+ if (devices.length === 0) {
277
+ deviceList.innerHTML = '<option value="">No devices found</option>';
278
+ return;
279
+ }
280
+
281
+ devices.forEach(device => {
282
+ const option = document.createElement('option');
283
+ option.value = device.id;
284
+ option.textContent = device.name;
285
+ deviceList.appendChild(option);
286
+ });
287
+ }
288
+
289
+ // Set up event listeners
290
+ function setupEventListeners() {
291
+ // Connect button
292
+ connectBtn.addEventListener('click', function() {
293
+ if (isConnected) {
294
+ disconnectFromDrone();
295
+ } else {
296
+ const selectedDeviceId = deviceList.value;
297
+ if (selectedDeviceId) {
298
+ connectToDrone(selectedDeviceId);
299
+ } else {
300
+ logToConsole('Please select a device first');
301
+ }
302
+ }
303
+ });
304
+
305
+ // Refresh button
306
+ refreshBtn.addEventListener('click', function() {
307
+ logToConsole('Scanning for BLE devices...');
308
+ // Simulate scanning delay
309
+ setTimeout(() => {
310
+ populateDeviceList();
311
+ logToConsole(`Found ${devices.length} device(s)`);
312
+ }, 1000);
313
+ });
314
+
315
+ // Action buttons
316
+ takeoffBtn.addEventListener('click', function() {
317
+ if (isConnected) {
318
+ takeoff();
319
+ }
320
+ });
321
+
322
+ landBtn.addEventListener('click', function() {
323
+ if (isConnected && isFlying) {
324
+ land();
325
+ }
326
+ });
327
+
328
+ emergencyBtn.addEventListener('click', function() {
329
+ if (isConnected) {
330
+ emergencyStop();
331
+ }
332
+ });
333
+
334
+ // Trim buttons
335
+ document.querySelectorAll('.trim-btn').forEach(btn => {
336
+ btn.addEventListener('click', function() {
337
+ const axis = this.dataset.axis;
338
+ const direction = this.dataset.direction;
339
+ adjustTrim(axis, direction);
340
+ });
341
+ });
342
+
343
+ // Flight mode selector
344
+ flightMode.addEventListener('change', function() {
345
+ if (isConnected) {
346
+ const mode = this.value;
347
+ setFlightMode(mode);
348
+ logToConsole(`Flight mode changed to: ${mode}`);
349
+ }
350
+ });
351
+
352
+ // Clear console
353
+ clearConsole.addEventListener('click', function() {
354
+ consoleOutput.innerHTML = '> Console cleared<br>';
355
+ });
356
+ }
357
+
358
+ // Set up joystick controls
359
+ function setupJoysticks() {
360
+ setupJoystick(leftJoystick, leftKnob, (x, y) => {
361
+ // Throttle (Y) and Yaw (X) controls
362
+ if (isConnected) {
363
+ const throttle = ((y * -1 + 1) / 2 * 100).toFixed(0);
364
+ const yaw = (x * 100).toFixed(0);
365
+ // In a real app, send these values to the drone via BLE
366
+ logToConsole(`Throttle: ${throttle}%, Yaw: ${yaw}%`, true);
367
+ }
368
+ });
369
+
370
+ setupJoystick(rightJoystick, rightKnob, (x, y) => {
371
+ // Pitch (Y) and Roll (X) controls
372
+ if (isConnected) {
373
+ const pitch = (y * 100).toFixed(0);
374
+ const roll = (x * 100).toFixed(0);
375
+ // In a real app, send these values to the drone via BLE
376
+ logToConsole(`Pitch: ${pitch}%, Roll: ${roll}%`, true);
377
+ }
378
+ });
379
+ }
380
+
381
+ // Helper function to set up a joystick
382
+ function setupJoystick(joystick, knob, callback) {
383
+ let isDragging = false;
384
+
385
+ // Touch events
386
+ joystick.addEventListener('touchstart', handleStart);
387
+ joystick.addEventListener('touchmove', handleMove);
388
+ joystick.addEventListener('touchend', handleEnd);
389
+
390
+ // Mouse events
391
+ joystick.addEventListener('mousedown', handleStart);
392
+ document.addEventListener('mousemove', handleMove);
393
+ document.addEventListener('mouseup', handleEnd);
394
+
395
+ function handleStart(e) {
396
+ e.preventDefault();
397
+ isDragging = true;
398
+ updatePosition(e);
399
+ }
400
+
401
+ function handleMove(e) {
402
+ if (!isDragging) return;
403
+ e.preventDefault();
404
+ updatePosition(e);
405
+ }
406
+
407
+ function handleEnd(e) {
408
+ isDragging = false;
409
+ // Return knob to center
410
+ knob.style.transform = 'translate(-50%, -50%)';
411
+ callback(0, 0);
412
+ }
413
+
414
+ function updatePosition(e) {
415
+ const rect = joystick.getBoundingClientRect();
416
+ const centerX = rect.left + rect.width / 2;
417
+ const centerY = rect.top + rect.height / 2;
418
+
419
+ let clientX, clientY;
420
+
421
+ if (e.type.includes('touch')) {
422
+ clientX = e.touches[0].clientX;
423
+ clientY = e.touches[0].clientY;
424
+ } else {
425
+ clientX = e.clientX;
426
+ clientY = e.clientY;
427
+ }
428
+
429
+ const x = clientX - centerX;
430
+ const y = clientY - centerY;
431
+
432
+ // Calculate distance from center
433
+ const distance = Math.sqrt(x * x + y * y);
434
+ const maxDistance = rect.width / 2 - 25; // 25 is half knob width
435
+
436
+ // Normalized values (-1 to 1)
437
+ let normX = x / maxDistance;
438
+ let normY = y / maxDistance;
439
+
440
+ // Limit to joystick bounds
441
+ if (distance > maxDistance) {
442
+ normX = (x / distance) * 1;
443
+ normY = (y / distance) * 1;
444
+ }
445
+
446
+ // Update knob position
447
+ knob.style.transform = `translate(${normX * 35}px, ${normY * 35}px) translate(-50%, -50%)`;
448
+
449
+ // Call callback with normalized values
450
+ callback(normX, normY);
451
+ }
452
+ }
453
+
454
+ // Connect to drone (simulated)
455
+ function connectToDrone(deviceId) {
456
+ logToConsole(`Connecting to device ${deviceId}...`);
457
+
458
+ // Simulate connection delay
459
+ setTimeout(() => {
460
+ isConnected = true;
461
+ updateConnectionStatus(true);
462
+ enableControls();
463
+
464
+ // Start battery simulation
465
+ startBatterySimulation();
466
+
467
+ logToConsole('Connected successfully!');
468
+ logToConsole('PicoDrone ready for commands');
469
+
470
+ // Update device name in UI
471
+ const device = devices.find(d => d.id === deviceId);
472
+ if (device) {
473
+ connectionText.textContent = device.name;
474
+ }
475
+ }, 1500);
476
+ }
477
+
478
+ // Disconnect from drone (simulated)
479
+ function disconnectFromDrone() {
480
+ logToConsole('Disconnecting from drone...');
481
+
482
+ // Stop any ongoing processes
483
+ if (isFlying) {
484
+ emergencyStop();
485
+ }
486
+
487
+ if (batterySimulator) {
488
+ clearInterval(batterySimulator);
489
+ batterySimulator = null;
490
+ }
491
+
492
+ if (flightTimer) {
493
+ clearInterval(flightTimer);
494
+ flightTimer = null;
495
+ }
496
+
497
+ // Simulate disconnection delay
498
+ setTimeout(() => {
499
+ isConnected = false;
500
+ isFlying = false;
501
+ updateConnectionStatus(false);
502
+ disableControls();
503
+
504
+ // Reset status displays
505
+ batteryLevel.style.width = '0%';
506
+ batteryPercent.textContent = '0%';
507
+ signalLevel.style.width = '0%';
508
+ signalPercent.textContent = '-';
509
+ altitudeValue.textContent = '0.0 m';
510
+ speedValue.textContent = '0.0 m/s';
511
+ flightTime.textContent = '00:00';
512
+
513
+ logToConsole('Disconnected successfully');
514
+ connectionText.textContent = 'Disconnected';
515
+ }, 1000);
516
+ }
517
+
518
+ // Update connection status UI
519
+ function updateConnectionStatus(connected) {
520
+ if (connected) {
521
+ connectionStatus.classList.remove('bg-red-500');
522
+ connectionStatus.classList.add('bg-green-500', 'connection-pulse');
523
+ connectionText.textContent = 'Connected';
524
+ connectBtn.innerHTML = '<i class="fas fa-unplug mr-2"></i> Disconnect';
525
+ connectBtn.classList.remove('bg-green-600', 'hover:bg-green-700');
526
+ connectBtn.classList.add('bg-red-600', 'hover:bg-red-700');
527
+ } else {
528
+ connectionStatus.classList.remove('bg-green-500', 'connection-pulse');
529
+ connectionStatus.classList.add('bg-red-500');
530
+ connectionText.textContent = 'Disconnected';
531
+ connectBtn.innerHTML = '<i class="fas fa-plug mr-2"></i> Connect to Drone';
532
+ connectBtn.classList.remove('bg-red-600', 'hover:bg-red-700');
533
+ connectBtn.classList.add('bg-green-600', 'hover:bg-green-700');
534
+ }
535
+ }
536
+
537
+ // Enable flight controls
538
+ function enableControls() {
539
+ takeoffBtn.disabled = false;
540
+ landBtn.disabled = !isFlying;
541
+ emergencyBtn.disabled = false;
542
+ }
543
+
544
+ // Disable flight controls
545
+ function disableControls() {
546
+ takeoffBtn.disabled = true;
547
+ landBtn.disabled = true;
548
+ emergencyBtn.disabled = true;
549
+ }
550
+
551
+ // Takeoff command
552
+ function takeoff() {
553
+ if (!isFlying) {
554
+ logToConsole('Initiating takeoff sequence...');
555
+
556
+ // Simulate takeoff delay
557
+ setTimeout(() => {
558
+ isFlying = true;
559
+ flightStartTime = new Date();
560
+ startFlightTimer();
561
+ landBtn.disabled = false;
562
+
563
+ logToConsole('Drone is airborne!');
564
+
565
+ // Simulate altitude increase
566
+ let altitude = 0;
567
+ const altitudeInterval = setInterval(() => {
568
+ if (!isFlying) {
569
+ clearInterval(altitudeInterval);
570
+ return;
571
+ }
572
+
573
+ altitude += 0.1;
574
+ if (altitude > 10) altitude = 10; // Max altitude for demo
575
+ altitudeValue.textContent = altitude.toFixed(1) + ' m';
576
+ }, 200);
577
+ }, 2000);
578
+ }
579
+ }
580
+
581
+ // Land command
582
+ function land() {
583
+ if (isFlying) {
584
+ logToConsole('Initiating landing sequence...');
585
+
586
+ // Simulate landing delay
587
+ setTimeout(() => {
588
+ isFlying = false;
589
+ if (flightTimer) {
590
+ clearInterval(flightTimer);
591
+ flightTimer = null;
592
+ }
593
+ landBtn.disabled = true;
594
+
595
+ logToConsole('Drone has landed safely');
596
+
597
+ // Simulate altitude decrease
598
+ let altitude = parseFloat(altitudeValue.textContent);
599
+ const altitudeInterval = setInterval(() => {
600
+ altitude -= 0.2;
601
+ if (altitude < 0) {
602
+ altitude = 0;
603
+ clearInterval(altitudeInterval);
604
+ }
605
+ altitudeValue.textContent = altitude.toFixed(1) + ' m';
606
+ }, 200);
607
+ }, 2000);
608
+ }
609
+ }
610
+
611
+ // Emergency stop command
612
+ function emergencyStop() {
613
+ logToConsole('EMERGENCY STOP ACTIVATED!', false, 'text-red-500');
614
+
615
+ // Immediate stop
616
+ isFlying = false;
617
+ if (flightTimer) {
618
+ clearInterval(flightTimer);
619
+ flightTimer = null;
620
+ }
621
+ landBtn.disabled = true;
622
+
623
+ // Simulate rapid descent
624
+ let altitude = parseFloat(altitudeValue.textContent);
625
+ const crashInterval = setInterval(() => {
626
+ altitude -= 0.5;
627
+ if (altitude <= 0) {
628
+ altitude = 0;
629
+ clearInterval(crashInterval);
630
+ logToConsole('Drone has crashed!', false, 'text-red-500');
631
+ }
632
+ altitudeValue.textContent = altitude.toFixed(1) + ' m';
633
+ }, 100);
634
+ }
635
+
636
+ // Adjust trim
637
+ function adjustTrim(axis, direction) {
638
+ if (isConnected) {
639
+ logToConsole(`Adjusting ${axis} trim: ${direction}`);
640
+ // In a real app, send trim commands to the drone
641
+ }
642
+ }
643
+
644
+ // Set flight mode
645
+ function setFlightMode(mode) {
646
+ // In a real app, send flight mode command to the drone
647
+ }
648
+
649
+ // Start flight timer
650
+ function startFlightTimer() {
651
+ flightTimer = setInterval(() => {
652
+ const now = new Date();
653
+ const diff = now - flightStartTime;
654
+ const minutes = Math.floor(diff / 60000);
655
+ const seconds = Math.floor((diff % 60000) / 1000);
656
+ flightTime.textContent =
657
+ `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
658
+
659
+ // Simulate speed changes
660
+ const speed = (0.5 + Math.random() * 2).toFixed(1);
661
+ speedValue.textContent = `${speed} m/s`;
662
+
663
+ // Simulate signal strength fluctuations
664
+ const signal = 70 + Math.floor(Math.random() * 30);
665
+ signalLevel.style.width = `${signal}%`;
666
+ signalPercent.textContent = `${signal}%`;
667
+ }, 1000);
668
+ }
669
+
670
+ // Simulate battery drain
671
+ function startBatterySimulation() {
672
+ let battery = 75; // Start at 75%
673
+ batteryLevel.style.width = `${battery}%`;
674
+ batteryPercent.textContent = `${battery}%`;
675
+
676
+ batterySimulator = setInterval(() => {
677
+ if (!isConnected) return;
678
+
679
+ // Drain faster when flying
680
+ const drainRate = isFlying ? 0.5 : 0.1;
681
+ battery -= drainRate;
682
+
683
+ if (battery < 0) battery = 0;
684
+
685
+ batteryLevel.style.width = `${battery}%`;
686
+ batteryPercent.textContent = `${Math.floor(battery)}%`;
687
+
688
+ // Change color based on level
689
+ if (battery < 20) {
690
+ batteryLevel.classList.remove('bg-green-500', 'bg-yellow-500');
691
+ batteryLevel.classList.add('bg-red-500');
692
+ } else if (battery < 50) {
693
+ batteryLevel.classList.remove('bg-green-500', 'bg-red-500');
694
+ batteryLevel.classList.add('bg-yellow-500');
695
+ } else {
696
+ batteryLevel.classList.remove('bg-yellow-500', 'bg-red-500');
697
+ batteryLevel.classList.add('bg-green-500');
698
+ }
699
+
700
+ // Critical battery warning
701
+ if (battery < 10 && isFlying) {
702
+ logToConsole('WARNING: Critical battery level! Land immediately!', false, 'text-red-500');
703
+ } else if (battery < 20) {
704
+ logToConsole('Warning: Low battery', false, 'text-yellow-500');
705
+ }
706
+
707
+ // Auto-land at 5% if flying
708
+ if (battery <= 5 && isFlying) {
709
+ logToConsole('AUTO-LANDING: Battery critically low', false, 'text-red-500');
710
+ land();
711
+ }
712
+ }, 1000);
713
+ }
714
+
715
+ // Log messages to console
716
+ function logToConsole(message, isCommand = false, colorClass = '') {
717
+ const now = new Date();
718
+ const timestamp = now.toLocaleTimeString();
719
+ const messageElement = document.createElement('div');
720
+
721
+ if (colorClass) {
722
+ messageElement.className = colorClass;
723
+ }
724
+
725
+ messageElement.innerHTML = `&gt; [${timestamp}] ${message}`;
726
+ consoleOutput.appendChild(messageElement);
727
+ consoleOutput.scrollTop = consoleOutput.scrollHeight;
728
+ }
729
+
730
+ // Initialize the app
731
+ init();
732
+ });
733
+ </script>
734
+ <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=privateuserh/privdrone" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
735
+ </html>