🔧 AI Nachrichten ChatGPT showing blank screen [Fix](05.09.2026 um 19:55 Uhr)
⚠️ Malware / Trojaner / VirenSofort deinstallieren: Diese 19 Browser-Erweiterungen sind mit Malware verseucht(06.09.2026 um 08:00 Uhr)
⚠️ Malware / Trojaner / VirenLumma Stealer – dllhost.exe Hollowing, C2 Domains & Payload Extraction(01.09.2026 um 17:19 Uhr)
🔧 AI Nachrichten Simcha Kosman AMA: Owning ChatGPT's Secure Sandbox(03.09.2026 um 07:41 Uhr)
⚠️ Malware / Trojaner / VirenThe Gentlemen Ransomware Analysis: Go Obfuscated(04.09.2026 um 12:05 Uhr)
⚠️ Malware / Trojaner / VirenTengu, a Mirai-style Linux and IoT botnet(06.09.2026 um 15:27 Uhr)
🔧 AI Nachrichten ChatGPT showing blank screen [Fix](05.09.2026 um 19:55 Uhr)
⚠️ Malware / Trojaner / VirenSofort deinstallieren: Diese 19 Browser-Erweiterungen sind mit Malware verseucht(06.09.2026 um 08:00 Uhr)
⚠️ Malware / Trojaner / VirenLumma Stealer – dllhost.exe Hollowing, C2 Domains & Payload Extraction(01.09.2026 um 17:19 Uhr)
🔧 AI Nachrichten Simcha Kosman AMA: Owning ChatGPT's Secure Sandbox(03.09.2026 um 07:41 Uhr)
⚠️ Malware / Trojaner / VirenThe Gentlemen Ransomware Analysis: Go Obfuscated(04.09.2026 um 12:05 Uhr)
⚠️ Malware / Trojaner / VirenTengu, a Mirai-style Linux and IoT botnet(06.09.2026 um 15:27 Uhr)

🔧 Programmierung 🕛 kürzlich 6 Min Lesezeit
0

How I synced BLE firmware with React Native

↗ Quelle (dev.to)
🗣️ Stimme:

I've been building a mobile app for a smartwatch, and the hardest

part wasn't the UI. It was getting the phone to find the watch,

connect over Bluetooth, and keep that connection alive.



The watch runs custom firmware. The app is React Native with Expo.

There's no SDK, no nice wrapper library from the hardware team.

Just a protocol spec and a lot of trial and error.



This post is about that connection layer only: scanning, pairing,

subscribing to the BLE channel, and handling drops. What you do

after you're connected (time sync, notifications, calibration) is

a separate story.



The setup



Most embedded BLE devices expose a UART-style service with one

characteristic for writing from the phone and one for receiving

notifications from the device. The exact UUIDs come from your

firmware docs; you plug them in once and move on.



On the React Native side I'm using react-native-ble-manager.

It doesn't hide much. You scan, connect, subscribe to

characteristics, and write raw bytes. That's actually fine once

you accept that's the job.



Everything lives in a custom hook called useBleManager that

wraps the library and exposes the functions the rest of the app

calls once a device is connected.



The handshake packet



Even the initial connection needs a properly formatted packet.

The firmware expects a binary frame: start marker, flag, command

code, sequence number, payload, checksum, end marker.



I use buildPayload to format the handshake before the first write:




CODE
export function buildPayload(
flag: number,
commandCode: number,
seq: number,
payload: string | number[],
) {
const dataBuffer =
typeof payload === "string" ? [...Buffer.from(payload)] : payload;

const escapedDataBuffer = escapePayload(dataBuffer);
const checksum = calculateChecksum([flag, commandCode, seq, ...dataBuffer]);

return Buffer.from([
FLAGS.START_BYTE,
flag,
commandCode,
seq,
...escapedDataBuffer,
checksum,
FLAGS.END_BYTE,
]).toJSON().data;
}






The checksum is calculated on the original payload, not the

escaped bytes you transmit. I lost a day to that.



Scanning for the device



Pairing starts when the user puts the watch into discoverable

mode on ours, that means holding a button until it vibrates.



The hook scans and filters devices by the name the firmware

advertises:




CODE
const startScan = async () => {
setIsScanning(true);
await BleManager.scan([], SCAN_DURATION, false, {
matchMode: BleScanMatchMode.Sticky,
scanMode: BleScanMode.LowLatency,
});
};

const handleDiscoverPeripheral = (peripheral: Peripheral) => {
if (peripheral.name?.toLowerCase().includes("your-device-name")) {
setPeripherals((map) => new Map(map.set(peripheral.id, peripheral)));
}
};






When the scan finishes, the user picks a device from the list.



Connecting



After the user taps a device, connectPeripheral runs the full

sequence:




CODE
const connectPeripheral = async (
peripheral: Peripheral,
callback: () => void
) => {
await BleManager.connect(peripheral.id);
await sleep(900);

await startPeripheralNotification(peripheral.id);
await sleep(1000);

callback();
};






The sleeps aren't optional decoration. BLE needs a moment after

connect before you start reading and writing. I tried skipping

them early on and got random failures that disappeared the moment

I added delays back.



startPeripheralNotification does the actual setup:




CODE
const startPeripheralNotification = async (deviceId: string) => {
await BleManager.retrieveServices(deviceId);
await BleManager.startNotification(deviceId, SERVICE_UUID, TX_UUID);
await BleManager.write(deviceId, SERVICE_UUID, RX_UUID, handshakePacket);
};






Three steps, always in this order:




  1. Retrieve services

  2. Start notifications on the TX characteristic

  3. Send the handshake write to the RX characteristic



That third step is what tells the firmware the phone is ready.

Without it, you're connected at the Bluetooth level but the

device doesn't know you're there.



Writing to the device



Once connected, every outgoing packet goes through the same path:




CODE
const writeToPeripheral = async (payload: number[]) => {
if (!selectedPeripheralRef.current?.peripheral?.connected) return;

await BleManager.write(
selectedPeripheralRef.current.peripheral.id,
SERVICE_UUID,
RX_UUID,
payload,
);
};






The hook keeps a ref to the currently connected device so any

screen can write without passing the device ID around.



Staying connected



Watches disconnect more than you'd expect. Users walk away,

phones lock, radios get busy.



When a drop happens, the disconnect listener fires and retry

kicks in:




CODE
const handleDisconnectedPeripheral = (
event: BleDisconnectPeripheralEvent
) => {
setPeripherals((map) => {
const device = map.get(event.peripheral);
if (device) device.connected = false;
return new Map(map);
});

const disconnected = peripherals.get(event.peripheral);
if (disconnected) {
connectPeripheralWithRetry(disconnected, () => {});
}
};

const connectPeripheralWithRetry = async (
peripheral: Peripheral,
callback: () => void
) => {
while (true) {
try {
await connectPeripheral(peripheral, callback);
break;
} catch (err) {
console.error("Connection failed, retrying...", err);
}
}
};






Auto-reconnect saved us from a lot of problems we never had to

debug in production.



Bootstrapping the hook



On mount, the hook starts the BLE manager, requests permissions,

and registers listeners:




CODE
useEffect(() => {
BleManager.start({ showAlert: true });

const listeners = [
bleManagerEmitter.addListener(
"BleManagerDiscoverPeripheral",
handleDiscoverPeripheral
),
bleManagerEmitter.addListener(
"BleManagerStopScan",
handleStopScan
),
bleManagerEmitter.addListener(
"BleManagerDisconnectPeripheral",
handleDisconnectedPeripheral
),
];

handleAndroidPermissions();

return () => listeners.forEach((listener) => listener.remove());
}, []);






Android permissions



iOS mostly works if you declare the Bluetooth usage description

in your Info.plist.



Android is another story. Before Android 12 you need location

permission to scan. From Android 12 onward you need separate

Bluetooth scan and connect permissions at runtime.




CODE
const handleAndroidPermissions = () => {
if (Platform.OS === "android" && Platform.Version >= 31) {
PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
]);
} else if (Platform.OS === "android" && Platform.Version >= 23) {
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
);
}
};






I also used an Expo config plugin to inject the right manifest

entries. Without that, the app builds fine and then silently

fails to find any devices. Fun.



What I'd do differently



Log the handshake. Log every byte you send and receive during

the first connect. Most of my early bugs were visible in the hex

output within five minutes.



Don't skip the delays. If connect works sometimes but not

always, add a sleep before your first write. BLE timing is

finicky and fighting it costs more time than waiting.



Test disconnects on purpose. Walk away from your desk. Lock

your phone. Toggle airplane mode. Connection code that only works

on a happy path isn't done.



Keep connection logic in one hook. Scanning, connecting,

writing, and reconnecting all live in useBleManager. Screens

just call togglePeripheralConnection and move on.



Where it stands now



The app finds the device, connects, completes the handshake, and

reconnects when the link drops. Once that pipeline is stable,

everything else — time sync, notifications, calibration — builds

on top of the same writeToPeripheral path.



If you're trying to connect React Native to custom BLE firmware,

start here. Get scan, connect, and handshake working in isolation

before you touch any UI. The device doesn't care about your

component library. It only cares that you found it, stayed

connected, and sent the right bytes to say hello.



That's the whole game for this part.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 41%
🟡 In Evaluierung 29%
🟢 Keine Auswirkung 16%
Spannende Innovation 14%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
2 Quellen
Creator Panel – One Creator, Full Production: Der neue Creator Workflow
1 Quelle
ChatGPT showing blank screen [Fix]
1 Quelle
Sofort deinstallieren: Diese 19 Browser-Erweiterungen sind mit Malware verseucht
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten How I synced BLE firmware with React Native

Thematisch verwandte Begriffe: synced, firmware, with, React · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...