cduss commited on
Commit
fec6368
·
1 Parent(s): f6bf683
Files changed (1) hide show
  1. index.html +312 -18
index.html CHANGED
@@ -1,19 +1,313 @@
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
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>ReachyMini Controller</title>
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
17
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
18
+ min-height: 100vh;
19
+ display: flex;
20
+ justify-content: center;
21
+ align-items: center;
22
+ padding: 20px;
23
+ }
24
+
25
+ .container {
26
+ background: white;
27
+ border-radius: 20px;
28
+ padding: 40px;
29
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
30
+ max-width: 500px;
31
+ width: 100%;
32
+ }
33
+
34
+ h1 {
35
+ color: #333;
36
+ margin-bottom: 10px;
37
+ font-size: 28px;
38
+ }
39
+
40
+ .status {
41
+ padding: 12px;
42
+ border-radius: 8px;
43
+ margin: 20px 0;
44
+ font-weight: 500;
45
+ text-align: center;
46
+ }
47
+
48
+ .status.disconnected {
49
+ background: #fee;
50
+ color: #c33;
51
+ }
52
+
53
+ .status.connected {
54
+ background: #efe;
55
+ color: #3c3;
56
+ }
57
+
58
+ .status.connecting {
59
+ background: #ffeaa7;
60
+ color: #d63031;
61
+ }
62
+
63
+ .connect-btn {
64
+ width: 100%;
65
+ padding: 15px;
66
+ background: #667eea;
67
+ color: white;
68
+ border: none;
69
+ border-radius: 10px;
70
+ font-size: 16px;
71
+ font-weight: 600;
72
+ cursor: pointer;
73
+ transition: all 0.3s;
74
+ margin-bottom: 30px;
75
+ }
76
+
77
+ .connect-btn:hover {
78
+ background: #5568d3;
79
+ transform: translateY(-2px);
80
+ box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
81
+ }
82
+
83
+ .connect-btn:disabled {
84
+ background: #ccc;
85
+ cursor: not-allowed;
86
+ transform: none;
87
+ }
88
+
89
+ .commands {
90
+ display: grid;
91
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
92
+ gap: 15px;
93
+ }
94
+
95
+ .command-btn {
96
+ padding: 20px;
97
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
98
+ color: white;
99
+ border: none;
100
+ border-radius: 10px;
101
+ font-size: 14px;
102
+ font-weight: 600;
103
+ cursor: pointer;
104
+ transition: all 0.3s;
105
+ text-transform: uppercase;
106
+ letter-spacing: 0.5px;
107
+ }
108
+
109
+ .command-btn:hover:not(:disabled) {
110
+ transform: translateY(-3px);
111
+ box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
112
+ }
113
+
114
+ .command-btn:active:not(:disabled) {
115
+ transform: translateY(-1px);
116
+ }
117
+
118
+ .command-btn:disabled {
119
+ opacity: 0.5;
120
+ cursor: not-allowed;
121
+ transform: none;
122
+ }
123
+
124
+ .log {
125
+ margin-top: 30px;
126
+ padding: 15px;
127
+ background: #f8f9fa;
128
+ border-radius: 8px;
129
+ max-height: 200px;
130
+ overflow-y: auto;
131
+ font-size: 12px;
132
+ font-family: 'Courier New', monospace;
133
+ }
134
+
135
+ .log-entry {
136
+ padding: 5px 0;
137
+ border-bottom: 1px solid #e9ecef;
138
+ }
139
+
140
+ .log-entry:last-child {
141
+ border-bottom: none;
142
+ }
143
+
144
+ .log-entry.error {
145
+ color: #c33;
146
+ }
147
+
148
+ .log-entry.success {
149
+ color: #3c3;
150
+ }
151
+
152
+ .note {
153
+ margin-top: 20px;
154
+ padding: 15px;
155
+ background: #fff3cd;
156
+ border-left: 4px solid #ffc107;
157
+ border-radius: 4px;
158
+ font-size: 14px;
159
+ color: #856404;
160
+ }
161
+ </style>
162
+ </head>
163
+
164
+ <body>
165
+ <div class="container">
166
+ <h1>🤖 ReachyMini Controller</h1>
167
+
168
+ <div id="status" class="status disconnected">
169
+ Disconnected
170
  </div>
171
+
172
+ <button id="connectBtn" class="connect-btn">
173
+ Connect to ReachyMini
174
+ </button>
175
+
176
+ <div class="commands">
177
+ <button class="command-btn" data-command="forward" disabled>Forward</button>
178
+ <button class="command-btn" data-command="backward" disabled>Backward</button>
179
+ <button class="command-btn" data-command="left" disabled>Turn Left</button>
180
+ <button class="command-btn" data-command="right" disabled>Turn Right</button>
181
+ <button class="command-btn" data-command="stop" disabled>Stop</button>
182
+ <button class="command-btn" data-command="wave" disabled>Wave</button>
183
+ </div>
184
+
185
+ <div class="log" id="log"></div>
186
+
187
+ <div class="note">
188
+ <strong>Note:</strong> Web Bluetooth requires HTTPS. Make sure you're accessing this page securely. Your
189
+ browser must also support Web Bluetooth API (Chrome, Edge, Opera).
190
+ </div>
191
+ </div>
192
+
193
+ <script>
194
+ let device = null;
195
+ let characteristic = null;
196
+ const statusEl = document.getElementById('status');
197
+ const connectBtn = document.getElementById('connectBtn');
198
+ const commandBtns = document.querySelectorAll('.command-btn');
199
+ const logEl = document.getElementById('log');
200
+
201
+ // Check if Web Bluetooth is supported
202
+ if (!navigator.bluetooth) {
203
+ updateStatus('Web Bluetooth not supported', 'disconnected');
204
+ addLog('ERROR: Web Bluetooth API not available in this browser', 'error');
205
+ connectBtn.disabled = true;
206
+ }
207
+
208
+ function addLog(message, type = '') {
209
+ const entry = document.createElement('div');
210
+ entry.className = `log-entry ${type}`;
211
+ const timestamp = new Date().toLocaleTimeString();
212
+ entry.textContent = `[${timestamp}] ${message}`;
213
+ logEl.appendChild(entry);
214
+ logEl.scrollTop = logEl.scrollHeight;
215
+ }
216
+
217
+ function updateStatus(message, state) {
218
+ statusEl.textContent = message;
219
+ statusEl.className = `status ${state}`;
220
+ }
221
+
222
+ async function connectToDevice() {
223
+ try {
224
+ updateStatus('Scanning for devices...', 'connecting');
225
+ addLog('Requesting Bluetooth device...');
226
+
227
+ device = await navigator.bluetooth.requestDevice({
228
+ filters: [{ name: 'ReachyMini' }],
229
+ optionalServices: ['0000ffe0-0000-1000-8000-00805f9b34fb'] // Common serial service UUID
230
+ });
231
+
232
+ addLog(`Found device: ${device.name}`);
233
+ updateStatus('Connecting...', 'connecting');
234
+
235
+ const server = await device.gatt.connect();
236
+ addLog('Connected to GATT server');
237
+
238
+ // Get the service (using common serial service UUID)
239
+ const service = await server.getPrimaryService('0000ffe0-0000-1000-8000-00805f9b34fb');
240
+ addLog('Got service');
241
+
242
+ // Get the characteristic (using common serial characteristic UUID)
243
+ characteristic = await service.getCharacteristic('0000ffe1-0000-1000-8000-00805f9b34fb');
244
+ addLog('Got characteristic');
245
+
246
+ updateStatus('Connected to ReachyMini', 'connected');
247
+ addLog('Successfully connected!', 'success');
248
+
249
+ connectBtn.textContent = 'Disconnect';
250
+ commandBtns.forEach(btn => btn.disabled = false);
251
+
252
+ device.addEventListener('gattserverdisconnected', onDisconnected);
253
+
254
+ } catch (error) {
255
+ addLog(`Connection failed: ${error.message}`, 'error');
256
+ updateStatus('Connection failed', 'disconnected');
257
+ console.error('Connection error:', error);
258
+ }
259
+ }
260
+
261
+ function onDisconnected() {
262
+ updateStatus('Disconnected', 'disconnected');
263
+ addLog('Device disconnected', 'error');
264
+ connectBtn.textContent = 'Connect to ReachyMini';
265
+ commandBtns.forEach(btn => btn.disabled = true);
266
+ characteristic = null;
267
+ device = null;
268
+ }
269
+
270
+ async function disconnect() {
271
+ if (device && device.gatt.connected) {
272
+ device.gatt.disconnect();
273
+ addLog('Manually disconnected');
274
+ }
275
+ }
276
+
277
+ async function sendCommand(command) {
278
+ if (!characteristic) {
279
+ addLog('Not connected to device', 'error');
280
+ return;
281
+ }
282
+
283
+ try {
284
+ const encoder = new TextEncoder();
285
+ const data = encoder.encode(command);
286
+ await characteristic.writeValue(data);
287
+ addLog(`Sent command: ${command}`, 'success');
288
+ } catch (error) {
289
+ addLog(`Failed to send command: ${error.message}`, 'error');
290
+ console.error('Send error:', error);
291
+ }
292
+ }
293
+
294
+ connectBtn.addEventListener('click', async () => {
295
+ if (device && device.gatt.connected) {
296
+ await disconnect();
297
+ } else {
298
+ await connectToDevice();
299
+ }
300
+ });
301
+
302
+ commandBtns.forEach(btn => {
303
+ btn.addEventListener('click', () => {
304
+ const command = btn.dataset.command;
305
+ sendCommand(command);
306
+ });
307
+ });
308
+
309
+ addLog('Ready. Click "Connect to ReachyMini" to start.');
310
+ </script>
311
+ </body>
312
+
313
+ </html>