Portenta C33 + UWB ShieldBLE Communication with ReactNative App

Portenta C33 + UWB Shield BLE Communication with React Native App

Sep 18, 2025 |

16 minutes read

Portenta C33 + UWB ShieldBLE Communication with ReactNative App

React Native BLE Integration

This project demonstrates wireless communication between the Arduino Portenta C33 microcontroller equipped with a UWB (Ultra-Wideband) Shield and a mobile application built with React Native. The Portenta C33 acts as a Bluetooth Low Energy (BLE) peripheral that advertises a custom UWB service. Through this service, a smartphone can connect, send commands, and receive responses in real time.

On the hardware side, the Portenta C33 manages BLE communication using the ArduinoBLE library and prepares for data exchange with the UWB shield over SPI (Serial Peripheral Interface). The device exposes two main characteristics:

  • Command Characteristic (Write-only): The phone sends commands such as turning the LED on/off or requesting UWB data.
  • Data Characteristic (Notify): The device responds with status updates or measurement results, which are instantly sent back to the phone.

On the software side, the React Native application uses the react-native-ble-plx library to scan for nearby BLE devices, establish a connection with the Portenta C33, and interact with the UWB service. The app provides a user-friendly interface for scanning, connecting, sending commands, and monitoring device responses.

This project highlights how modern microcontrollers and mobile applications can work together to create low-power, wireless, and interactive systems. While the current implementation demonstrates basic functionality with LED control and dummy UWB responses, it provides a foundation to integrate real UWB distance measurement data for applications such as indoor positioning, navigation, and smart IoT systems.

Hardware and Software Requirements

Hardware and Software Requirements

Hardware Requirements :

  • Portenta UWB Shield 
  • Portenta C33 
  • USB-C cable 

Software Requirements :

  • Arduino IDE 2.0+
  • Portenta UWB Shield library (for the Portenta UWB Shield)
  • Arduino Renesas Portenta Boards core (for the Portenta C33)

System Overview

The system consists of two main components: the embedded hardware platform and the mobile application interface. 

Embedded Hardware (Portenta C33 + UWB Shield):

The Portenta C33 microcontroller acts as the central controller. It communicates with the UWB shield over the SPI bus and simultaneously provides a Bluetooth Low Energy (BLE) interface to external devices. Using the ArduinoBLE library, the microcontroller advertises a custom UWB BLE service with two characteristics—command and data. Commands received from the phone (e.g., LED control, UWB request) are processed by the Portenta, and the results are sent back through the data characteristic as BLE notifications.

Mobile Application (React Native App)

A cross-platform React Native application enables the user to interact with the hardware. The app uses the react-native-ble-plx library to scan for nearby BLE devices, connect to the Portenta C33, and exchange data. It allows users to send commands such as turning the LED on/off or requesting UWB measurements, and it displays real-time responses received from the microcontroller.

Communication Flow:

  • The user interacts with the React Native app.
  • The app sends a command to the Portenta C33 over BLE.
  • The Portenta C33 processes the command and either controls the LED or communicates with the UWB shield to gather data.
  • The result is then sent back as a BLE notification to the mobile app, where it is displayed to the user.

This architecture demonstrates a complete IoT pipeline, where embedded hardware with wireless communication integrates seamlessly with a mobile application to provide a user-friendly, interactive, and extensible system.

System Architecture : 

The system consists of the following elements

System Architecture
  • The React Native mobile app connects via Bluetooth Low Energy (BLE).
  • The Portenta C33 handles BLE services and communicates with the UWB shield via SPI.
  • Commands flow from the app → Portenta → UWB shield, and responses flow back.

Hardware Setup

The hardware setup for this project consists of the Arduino Portenta C33, the Portenta UWB Shield, and connectivity with a computer and mobile phone. This setup enables the microcontroller to communicate with the shield over SPI and with the smartphone via Bluetooth Low Energy (BLE).

1. Required Components

  • Arduino Portenta C33 board
  • Portenta UWB Shield (compatible with Portenta family boards)
  • USB-C cable (for powering and programming the C33)
  • Computer with Arduino IDE installed
  • Smartphone (Android/iOS) with Bluetooth enabled and the React Native app installed

2. Assembly

  • Align the Boards
    • Place the Portenta UWB Shield directly below the Portenta C33.
    • Ensure that the high-density connectors of the UWB Shield and Portenta C33 are perfectly aligned.
    • Gently press the boards together until the connectors are fully seated.
    • Make sure the boards are flush and there is no gap between them.
    • Plug a USB-C cable into the Portenta C33.
    • Connect the other end to your computer for power and programming
Hardware Setup
  1. Powering the System

During development, the Portenta C33 is powered directly through the USB-C connection.
For standalone use, you can power the device with:

  • An external power source via the Portenta’s power pins, or
  • A battery pack compatible with the Portenta family.
  1. Connections

Portenta C33 ↔ UWB Shield → Communication through SPI bus.

Portenta C33 ↔ Smartphone → Wireless link using the built-in BLE module (no extra wiring required).

Portenta C33 ↔ Computer → USB-C for programming and serial debugging.

  1. Verification Steps
    1. Connect the hardware to your PC.
    2. Open Arduino IDE and select Portenta C33 as the target board.
    3. Upload the provided BLE sketch.
    4. Open the Serial Monitor at 115200 baud → You should see the message:

BLE advertising as Portenta-UWB

5. On your smartphone:

  1. Open the React Native app.
  2. Start scanning for devices.
  3. You should see Portenta-UWB in the device list.
  4. Connect to it and test with commands (e.g., LED:ON, LED:OFF)

Arduino Code

`
#include 
#include 
#include 

#define UWB_SERVICE_UUID   "12345678-1234-5678-1234-56789abcdef0"
#define CMD_CHAR_UUID      "12345678-1234-5678-1234-56789abcdef1"
#define DATA_CHAR_UUID     "12345678-1234-5678-1234-56789abcdef2"

BLEService uwbService(UWB_SERVICE_UUID);

BLECharacteristic cmdChar(CMD_CHAR_UUID, BLEWrite, 64);
BLECharacteristic dataChar(DATA_CHAR_UUID, BLENotify, 64);

void onCmdWritten(BLEDevice central, BLECharacteristic characteristic) {
  String cmd = "";
  int len = characteristic.valueLength();
  for (int i = 0; i < len; i++) {
    cmd += (char)characteristic.value()[i];
  }

  Serial.print("CMD from phone: "); 
  Serial.println(cmd);

  if (cmd == "LED:ON") {
    digitalWrite(LED_BUILTIN, HIGH);
    dataChar.writeValue("OK:LED_ON");
  } 
  else if (cmd == "LED:OFF") {
    digitalWrite(LED_BUILTIN, LOW);
    dataChar.writeValue("OK:LED_OFF");
  } 
  else if (cmd.startsWith("UWB:")) {
    String resp = "UWB_RESP:dummy";
    dataChar.writeValue(resp.c_str());
  } 
  else {
    dataChar.writeValue("ERR:UNKNOWN_CMD");
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial);

  pinMode(LED_BUILTIN, OUTPUT);

  if (!BLE.begin()) {
    Serial.println("Failed to init BLE!");
    while (1);
  }

  BLE.setLocalName("Portenta-UWB");
  BLE.setAdvertisedService(uwbService);
  uwbService.addCharacteristic(cmdChar);
  uwbService.addCharacteristic(dataChar);
  BLE.addService(uwbService);

  cmdChar.setEventHandler(BLEWritten, onCmdWritten);

  BLE.advertise();
  Serial.println("BLE advertising as Portenta-UWB");

  SPI.begin();
}

void loop() {
  BLE.poll();
}

`
import React, { useEffect, useState } from "react";
import {
  View,
  Text,
  Button,
  FlatList,
  TouchableOpacity,
  PermissionsAndroid,
  Platform,
} from "react-native";
import { BleManager } from "react-native-ble-plx";
import { Buffer } from "buffer";

const manager = new BleManager();

const UWB_SERVICE_UUID = "12345678-1234-5678-1234-56789abcdef0";
const CMD_CHAR_UUID = "12345678-1234-5678-1234-56789abcdef1";
const DATA_CHAR_UUID = "12345678-1234-5678-1234-56789abcdef2";

export default function App() {
  const [devices, setDevices] = useState([]);
  const [connectedDevice, setConnectedDevice] = useState(null);

  const startScan = async () => {
    setDevices([]);

    if (Platform.OS === "android" && Platform.Version >= 23) {
      await PermissionsAndroid.requestMultiple([
        PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
        PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
        PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
      ]);
    }

    manager.startDeviceScan(null, null, (error, device) => {
      if (error) {
        console.log("Scan error:", error);
        return;
      }

      if (device && device.name) {
        setDevices((prev) => {
          if (!prev.find((d) => d.id === device.id)) {
            return [...prev, device];
          }
          return prev;
        });
      }
    });

    setTimeout(() => manager.stopDeviceScan(), 10000);
  };

  useEffect(() => {
    startScan();
    return () => manager.destroy();
  }, []);

  const connectToDevice = async (device) => {
    try {
      const connected = await manager.connectToDevice(device.id);
      await connected.discoverAllServicesAndCharacteristics();
      setConnectedDevice(connected);
      console.log(" Connected to:", connected.name);

      connected.monitorCharacteristicForService(
        UWB_SERVICE_UUID,
        DATA_CHAR_UUID,
        (error, char) => {
          if (error) {
            console.log("Notify error:", error);
            return;
          }
          if (char?.value) {
            const msg = Buffer.from(char.value, "base64").toString("utf-8");
            console.log(" From board:", msg);
          }
        }
      );
    } catch (error) {
      console.log("Connection error:", error);
    }
  };

  const sendCommand = async (cmd) => {
    if (!connectedDevice) return;
    try {
      await connectedDevice.writeCharacteristicWithResponseForService(
        UWB_SERVICE_UUID,
        CMD_CHAR_UUID,
        Buffer.from(cmd, "utf-8").toString("base64")
      );
      console.log(" Sent:", cmd);
    } catch (error) {
      console.log("Write error:", error);
    }
  };

  return (
    
      Nearby BLE Devices

      
Output

Portenta UWB BLE project: Connect hardware & mobile

The Way Forward

Performance optimization in Magento 2 is essential for a fast, smooth shopping experience. By identifying bottlenecks and applying development enhancements like caching, code optimization, and database tuning, you can drastically improve site speed. Regular monitoring and best practices keep your store running efficiently. A well-optimized Magento store boosts user satisfaction, SEO, and sales. 

Free Consultation

    Lopa Das

    With over 13 years of experience, Lopa Das is a seasoned professional at iFlair Web Technologies Pvt Ltd, specializing in web and mobile app development. Her technical expertise spans across Laravel, PHP, CodeIgniter, CakePHP, React, Vue.js, Nuxt.js, iOS, Android, Flutter, and React Native. Known for her exceptional skills in team handling, client communication, presales, and risk analysis, Lopa ensures seamless project execution from start to finish. Her proficiency in Laravel CRM, Next.js, and mobile app development makes her a valuable asset in delivering robust, scalable solutions.



    MAP_New

    Global Footprints

    Served clients across the globe from38+ countries

    iFlair Web Technologies
    Privacy Overview

    This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.