Skip to content

Commit 74244c5

Browse files
authored
Merge pull request #6 from sensebox/fix/connectionIssues
fix: connection issues by using old old web-flash tool
2 parents b75bcb7 + 8ae27f2 commit 74244c5

7 files changed

Lines changed: 296 additions & 158 deletions

File tree

next-env.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3+
import "./.next/dev/types/routes.d.ts";
34

45
// NOTE: This file should not be edited
56
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

src/components/pages/BoardSelect.tsx

Lines changed: 131 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
'use client'
2-
import { useState } from 'react'
2+
import { useState, useRef } from 'react'
33
import { Button } from '@/components/ui/button'
44
import {
55
Card,
66
CardContent,
77
CardDescription,
88
CardFooter,
99
CardHeader,
10-
CardTitle,
1110
} from '@/components/ui/card'
1211
import { Label } from '@/components/ui/label'
1312
import {
@@ -21,13 +20,12 @@ import {
2120
FileText,
2221
Cpu,
2322
SearchIcon,
24-
Info,
2523
CheckCircle,
2624
InfoIcon,
2725
PlugZap,
2826
} from 'lucide-react'
29-
import { ESPLoader, FlashOptions, LoaderOptions, Transport } from 'esptool-js'
3027
import { Terminal } from '@xterm/xterm'
28+
import { EspTerminal } from '../../lib/espTerminal'
3129
import { Progress } from '../ui/progress'
3230
import { FourSquare } from 'react-loading-indicators'
3331
import {
@@ -36,19 +34,14 @@ import {
3634
AccordionItem,
3735
AccordionTrigger,
3836
} from '../ui/accordion'
39-
let esploader: ESPLoader
40-
let transport: Transport
41-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
42-
let device: any = null
37+
import { connectESP, formatMacAddr, sleep } from '../../lib/esp'
38+
4339
interface BoardSelectProps {
4440
terminal: Terminal | null
4541
}
4642

4743
export default function BoardSelect({ terminal }: BoardSelectProps) {
4844
// Prüfe, ob der Browser die serielle API unterstützt
49-
const [canUseSerial] = useState(() => 'serial' in navigator)
50-
const serial = navigator['serial']
51-
5245
const [progress, setProgress] = useState<number>(0)
5346
const [sketch, setSketch] = useState<string>('')
5447
const [flashing, setFlashing] = useState<boolean>(false)
@@ -59,159 +52,157 @@ export default function BoardSelect({ terminal }: BoardSelectProps) {
5952
const [debugMode, setDebugMode] = useState<boolean>(false)
6053
const [baudRate, setBaudRate] = useState<number>(921600)
6154
const [selected, setSelected] = useState<string>('ota')
62-
// Falls der Browser keine serielle Unterstützung bietet,
63-
// wird hier ein Disclaimer angezeigt.
64-
if (!canUseSerial) {
65-
return (
66-
<Card className="flex h-full w-full flex-col border-2 border-slate-300 shadow-md">
67-
<CardHeader className="rounded-t-lg bg-white p-4">
68-
<div className="flex items-center space-x-2">
69-
<Info className="h-6 w-6" />
70-
<CardTitle className="font-bold">
71-
Browser nicht unterstützt
72-
</CardTitle>
73-
</div>
74-
<CardDescription className="font-semibold">
75-
Ihr Browser unterstützt die serielle Kommunikation nicht. Bitte
76-
verwenden Sie Opera, Chrome oder Edge.
77-
</CardDescription>
78-
</CardHeader>
79-
</Card>
80-
)
55+
interface EspStub {
56+
flashData?: (
57+
buffer: ArrayBuffer,
58+
onProgress: (bytesWritten: number, totalBytes: number) => void,
59+
offset: number,
60+
) => Promise<void>
61+
disconnect?: () => Promise<void>
62+
port?: {
63+
close?: () => Promise<void>
64+
addEventListener?: (event: string, handler: () => void) => void
65+
}
8166
}
67+
const [espStub, setEspStub] = useState<EspStub | undefined>(undefined)
8268

83-
const espLoaderTerminal = {
84-
clean() {
85-
terminal?.clear()
86-
},
87-
writeLine(data: string) {
88-
const match = data.match(/\((\d+)%\)/)
89-
if (match) {
90-
setProgress(parseInt(match[1], 10))
91-
}
69+
// Use refs for transport/device to avoid re-renders
70+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
71+
// @ts-expect-error
72+
const transportRef = useRef<Transport | null>(null)
73+
const deviceRef = useRef<unknown>(null)
9274

93-
if (data.includes('Hard resetting via RTS pin...')) {
94-
console.log('Upload abgeschlossen!')
95-
setProgress(100)
96-
setFlashing(false)
97-
setUploadSuccess(true) // Erfolgsmeldung setzen
98-
}
99-
100-
terminal?.writeln(data)
101-
},
102-
write(data: string) {
103-
terminal?.write(data)
104-
},
75+
// --- Modular helpers ---
76+
async function fetchFirmware(selected: string): Promise<ArrayBuffer> {
77+
let response
78+
switch (selected) {
79+
case 'ota':
80+
response = await fetch('/mergedOTA.bin')
81+
break
82+
case 'circuitpython':
83+
response = await fetch('/circuitpython9_2_8.bin')
84+
break
85+
case 'uf2':
86+
response = await fetch(
87+
'tinyuf2-sensebox_mcu_esp32s2-0.35.0-combined.bin',
88+
)
89+
break
90+
default:
91+
response = await fetch('/mergedOTA.bin')
92+
break
93+
}
94+
if (!response.ok) {
95+
throw new Error(`Fehler beim Abrufen der Datei: ${response.statusText}`)
96+
}
97+
return await response.arrayBuffer()
10598
}
10699

107-
const listSerialPorts = async () => {
108-
try {
109-
setError('') // Vorherige Fehler zurücksetzen
110-
device = await serial.requestPort({
111-
filters: [{ usbVendorId: 0x303a }],
112-
})
113-
transport = new Transport(device, true)
114-
115-
setConnecting(true)
116-
const flashOptions = {
117-
transport,
118-
baudrate: baudRate,
119-
terminal: espLoaderTerminal,
120-
debugLogging: debugMode,
121-
} as LoaderOptions
122-
123-
esploader = new ESPLoader(flashOptions)
124-
await esploader.main()
125-
setBoardFound(true)
126-
127-
let response
128-
// Lade die Datei "mergedOTA.bin" aus "public/"
129-
switch (selected) {
130-
case 'ota':
131-
response = await fetch('/mergedOTA.bin')
132-
break
133-
case 'circuitpython':
134-
response = await fetch('/circuitpython9_2_8.bin')
135-
break
136-
case 'uf2':
137-
response = await fetch(
138-
'tinyuf2-sensebox_mcu_esp32s2-0.35.0-combined.bin',
139-
)
140-
break
141-
default:
142-
response = await fetch('/mergedOTA.bin')
143-
break
144-
}
145-
146-
if (!response.ok) {
147-
throw new Error(`Fehler beim Abrufen der Datei: ${response.statusText}`)
148-
}
100+
function readFirmwareToSketch(buffer: ArrayBuffer) {
101+
const blob = new Blob([buffer])
102+
const reader = new FileReader()
103+
reader.onload = function () {
104+
setSketch(reader.result as string)
105+
}
106+
reader.onerror = function () {
107+
console.error('Fehler beim Lesen der Datei:', reader.error)
108+
setError('Fehler beim Lesen der Datei.')
109+
}
110+
reader.readAsBinaryString(blob)
111+
}
149112

150-
const buffer = await response.arrayBuffer()
151-
const blob = new Blob([buffer])
152-
const reader = new FileReader()
113+
// ...existing code...
153114

154-
reader.onload = function () {
155-
setSketch(reader.result as string)
156-
}
157-
reader.onerror = function () {
158-
console.error('Fehler beim Lesen der Datei:', reader.error)
159-
setError('Fehler beim Lesen der Datei.')
160-
}
115+
const espLoaderTerminal = new EspTerminal(terminal, {
116+
setProgress,
117+
setFlashing,
118+
setUploadSuccess,
119+
})
161120

162-
reader.readAsBinaryString(blob)
163-
} catch (error) {
164-
console.error('Fehler beim Auflisten der seriellen Ports:', error)
121+
const clickConnect = async () => {
122+
if (espStub) {
123+
await espStub.disconnect?.()
124+
await espStub.port?.close?.()
125+
setEspStub(undefined)
126+
return
127+
}
128+
const esploader = await connectESP({
129+
log: (...args: unknown[]) => espLoaderTerminal.writeLine(args.join(' ')),
130+
debug: (...args: unknown[]) =>
131+
espLoaderTerminal.writeLine('[DEBUG] ' + args.join(' ')),
132+
error: (...args: unknown[]) =>
133+
espLoaderTerminal.writeLine('[ERROR] ' + args.join(' ')),
134+
baudRate: baudRate,
135+
})
136+
setConnecting(true)
137+
await esploader.initialize()
138+
console.log(`Connected to ${esploader.chipName}`)
139+
console.log(`MAC Address: ${formatMacAddr(esploader.macAddr())}`)
140+
const newEspStub = await esploader.runStub()
141+
setConnecting(false)
142+
setEspStub(newEspStub)
143+
setBoardFound(true)
144+
try {
145+
const buffer = await fetchFirmware(selected)
146+
readFirmwareToSketch(buffer)
147+
} catch (err) {
165148
setError(
166-
'Fehler beim Auflisten der seriellen Ports: ' +
167-
(error instanceof Error ? error.message : error),
149+
'Fehler beim Laden der Firmware: ' +
150+
(err instanceof Error ? err.message : err),
168151
)
169-
setBoardFound(false)
170-
} finally {
171-
setConnecting(false)
172152
}
153+
newEspStub.port?.addEventListener?.('disconnect', () => {
154+
setBoardFound(false)
155+
setEspStub(undefined)
156+
console.log('Device disconnected')
157+
})
173158
}
174159

175-
const flashSketch = async () => {
160+
const program = async () => {
161+
setError('')
162+
setFlashing(true)
163+
setUploadSuccess(false)
176164
try {
177-
setError('') // Vorherige Fehler zurücksetzen
178-
setFlashing(true)
179-
setUploadSuccess(false) // Status zurücksetzen
180-
181-
const flashOptions: FlashOptions = {
182-
fileArray: [{ data: sketch, address: 0x0 }],
183-
flashSize: 'keep',
184-
eraseAll: true,
185-
compress: true,
186-
reportProgress: (fileIndex, written, total) => {
187-
setProgress((written / total) * 100)
165+
if (!espStub) {
166+
setError('ESP nicht verbunden.')
167+
setFlashing(false)
168+
return
169+
}
170+
const buffer = await fetchFirmware(selected)
171+
await espStub.flashData?.(
172+
buffer,
173+
(bytesWritten: number, totalBytes: number) => {
174+
const progress = bytesWritten / totalBytes
175+
const percentage = Math.floor(progress * 100)
176+
setProgress(percentage)
177+
espLoaderTerminal.writeLine(`Flashing... ${percentage}%`)
188178
},
189-
} as FlashOptions
190-
191-
await esploader.writeFlash(flashOptions)
192-
await esploader.after()
193-
} catch (error) {
194-
console.error('Fehler beim Flashen:', error)
195-
setError(
196-
'Fehler beim Flashen: ' +
197-
(error instanceof Error ? error.message : error),
179+
0x0,
198180
)
181+
await sleep(100)
182+
espLoaderTerminal.writeLine(`Done!`)
183+
espLoaderTerminal.writeLine(
184+
`To run the new firmware please reset your device.`,
185+
)
186+
setUploadSuccess(true)
187+
} catch (e) {
188+
console.error(e)
189+
setError('Fehler beim Flashen: ' + (e instanceof Error ? e.message : e))
199190
} finally {
200191
setFlashing(false)
201-
transport?.disconnect()
202192
}
203193
}
204194

205195
const disconnectBoard = async () => {
206196
try {
207-
console.log('Hallo')
208-
await transport?.disconnect() // Transport sauber schließen
209-
await device?.close() // Browser Serial-Port schließen
197+
await transportRef.current?.disconnect?.()
198+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
199+
// @ts-expect-error
200+
await deviceRef.current?.close?.()
210201
} catch (err) {
211202
console.error('Fehler beim Disconnect:', err)
212203
} finally {
213-
device = null // Reset globale Referenz
214-
setBoardFound(false) // State zurück
204+
deviceRef.current = null
205+
setBoardFound(false)
215206
setUploadSuccess(false)
216207
setError('')
217208
setSketch('')
@@ -264,7 +255,7 @@ export default function BoardSelect({ terminal }: BoardSelectProps) {
264255
) : (
265256
<Button
266257
id="boardSelect"
267-
onClick={listSerialPorts}
258+
onClick={clickConnect}
268259
className="w-full border-2 border-solid border-senseboxGreen bg-white text-senseboxGreen hover:bg-senseboxGreen/20"
269260
>
270261
<SearchIcon className="h-5 w-5" />
@@ -366,7 +357,7 @@ export default function BoardSelect({ terminal }: BoardSelectProps) {
366357
</CardContent>
367358
<CardFooter className="mt-auto p-4">
368359
<Button
369-
onClick={flashSketch}
360+
onClick={program}
370361
className="w-full bg-senseboxGreen text-white hover:bg-senseboxGreen/80"
371362
disabled={!boardFound || sketch === '' || flashing}
372363
>

0 commit comments

Comments
 (0)