fbpixel
Etiquetas: , , , ,
0
(0)

Vamos a ver cómo crear una aplicación React Native para Adnroid que permita la comunicación BLE (Bluetooth Low Energy) con un ESP32. Usaremos React Native para desarrollar un terminal BLE en Android que pueda comunicarse con un ESP32 NodeMCU o cualquier otro dispositivo compatible.

Hardware

  • Un ordenador con React Native y Node.js instalados
  • Un dispositivo Android con BLE
  • Un cable USB para conectar el ordenador al dispositivo
  • Un dispositivo BLE (ESP32)

Código de gestión BLE para ESP32

Para probar la aplicación React Native, vamos a utilizar el código de gestión BLE para ESP32.

/*
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleWrite.cpp
    Ported to Arduino ESP32 by Evandro Copercini
*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

BLECharacteristic *pCharacteristic = NULL;

std::string msg;

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();

      if (value.length() > 0) {
        Serial.println("*********");
        Serial.print("New value: ");
        for (int i = 0; i < value.length(); i++)
          Serial.print(value[i]);

        Serial.println();
        Serial.println("*********");
      }
    }
};

class MyServerCallbacks: public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    Serial.println("Client connected");
  }
  void onDisconnect(BLEServer* pServer) {
    Serial.println("Client disconnected");
    BLEDevice::startAdvertising(); // needed for reconnection
  }
};

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

  Serial.println("1- Download and install an BLE Terminal Free");
  Serial.println("2- Scan for BLE devices in the app");
  Serial.println("3- Connect to ESP32BLE");
  Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something");

  BLEDevice::init("ESP32BLE");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  
  BLEService *pService = pServer->createService(SERVICE_UUID);

  pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setCallbacks(new MyCallbacks());

  pCharacteristic->setValue("Hello World");
  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  pAdvertising->start();

  Serial.print("Server address:");
  Serial.println(BLEDevice::getAddress().toString().c_str());
}

void loop() {
  readSerialPort();

  //Send data to slave
  if(msg!=""){
    pCharacteristic->setValue(msg);
    msg="";
  }
  
  delay(2000);
}

void readSerialPort(){
 while (Serial.available()) {
   delay(10);  
   if (Serial.available() >0) {
     char c = Serial.read();  //gets one byte from serial buffer
     msg += c; //add to String
   }
 }
 Serial.flush(); //clean buffer
}

Añadimos la función BLEServerCallbacks a la gestión del Servidor BLE para detectar la desconexión e iniciar la publicidad para poder reconectar el ESP32.

  pServer->setCallbacks(new MyServerCallbacks());

Aplicación React Native para la gestión de BLE

Para gestionar la comunicación BLE (Bluetooth Low Energy) en el dispositivo Android, utilizamos la biblioteca react-native-ble-manager

npm install react-native-ble-manager --save

Para configurar el proyecto de aplicación, siga el tutorial anterior.

En el archivo App.tsx, para utilizar la biblioteca la importamos utilizando el comando

import BleManager from 'react-native-ble-manager';

Estamos creando un componente funcional que contendrá los elementos que necesitamos para gestionar la comunicación BLE

let serviceid="4fafc201-1fb5-459e-8fcc-c5c9c331914b";
let caracid="beb5483e-36e1-4688-b7f5-ea07361b26a8";

const BluetoothBLETerminal = () =>  {
 const [devices, setDevices] = useState<any[]>([]);
 const [paired, setPaired] = useState<any[]>([]);
 const [selectedDevice, setSelectedDevice] = useState<Peripheral>();
 const [messageToSend, setMessageToSend] = useState("");
 const [receivedMessage, setReceivedMessage] = useState("");
 const [isConnected, setIsConnected] = useState(false);
 const [intervalId, setIntervalId] = useState<NodeJS.Timer>();
 const [isScanning, setIsScanning] = useState(false);

N.B.: es posible crear un componente derivado de ReactNative.Components

Gestión de permisos

Para descubrir y conectarte a dispositivos Bluetooth, necesitas al menos 3 permisos:

  • BLUETOOTH_SCAN
  • BLUETOOTH_CONNECT
  • ACCESS_FINE_LOCATION

N.B.: estos permisos dependen de la versión y el SO utilizados

Estas son las etiquetas que hay que añadir al archivo AndroidManifest.xml

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.BLUETOOTH" />
  <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

En el archivo App.tsx, creamos la función requestBluetoothPermission()

    if (Platform.OS === 'android' && Platform.Version >= 23) {
  
        PermissionsAndroid.requestMultiple([
          PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
          PermissionsAndroid.PERMISSIONS.LIGAÇÃO_DE_DISTRIBUIÇÃO,
          PermissionsAndroid.PERMISSIONS.LOCALIZAÇÃO_DE_ACESSO,
        ]).then(result => {
          if (
            (result['android.permission.BLUETOOTH_SCAN'] &&
            result['android.permission.LIGAÇÃO_DE_DISTRIBUIÇÃO'] &&
            result['android.permission.LOCALIZAÇÃO_DE_ACESSO'] === 'granted')
            ||
            (result['android.permission.BLUETOOTH_SCAN'] &&
            result['android.permission.LIGAÇÃO_DE_DISTRIBUIÇÃO'] &&
            result['android.permission.LOCALIZAÇÃO_DE_ACESSO'] === 'never_ask_again')
          ) {
            console.log('User accepted');
          } else {
            console.log('User refused');        }
        });
    }

Función de gestión BLE

Las funciones para gestionar Bluetooth LE son las siguientes:

  • descubrir dispositivos bluetooth startDeviceDiscovery() (utilizo dispositivos emparejados)
  • conectar con el dispositivo connectToDevice()
  • desconectarDelDispositivo()
  • enviar mensajes sendMessage()
  • leer mensajes de la comunicación readData()

N.B.: En este ejemplo, estamos escribiendo y leyendo de la misma característica. Por lo tanto, leemos el valor registrado pulsando la tecla

const checkBluetoothEnabled = async () => {
   try {
         // turn on bluetooth if it is not on
   BleManager.enableBluetooth().then(() => {
     console.log('Bluetooth is turned on!');
   });
     
   } catch (error) {
     console.error('BLE is not available on this device.');
   }
 }
 
 const startScan = () => {
  if (!isScanning) {
    BleManager.scan([], 5, true)
      .then(() => {
        console.log('Scanning...');
        setIsScanning(true);
      })
      .catch(error => {
        console.error(error);
      });
  }
};

 const startDeviceDiscovery = async () => {

  BleManager.getBondedPeripherals().then((bondedPeripheralsArray) => {
    // Each peripheral in returned array will have id and name properties
    console.log("Bonded peripherals: " + bondedPeripheralsArray.length);
    setPaired(bondedPeripheralsArray);
  });

  /*BleManager.getDiscoveredPeripherals().then((peripheralsArray) => {
    // Success code
    console.log("Discovered peripherals: " + peripheralsArray.length);
  });*/
 }

 const connectToDevice = async (device: Peripheral) => {
 BleManager.connect(device.id)
     .then(() => {
     // Success code
     console.log("Connected");
     setSelectedDevice(device);
     setIsConnected(true);
     BleManager.retrieveServices(device.id).then(
       (deviceInfo) => {
       // Success code
       console.log("Device info:", deviceInfo);
       }
     );


     })
     .catch((error) => {
     // Failure code
     console.log(error);
     });
 }


const sendMessage = async () => {
 if(selectedDevice && isConnected){
   try {

    const buffer = Buffer.from(messageToSend);
    BleManager.write(
      selectedDevice.id,
      serviceid,
      caracid,
      buffer.toJSON().data
    ).then(() => {
      // Success code
      console.log("Write: " + buffer.toJSON().data);
    })
    .catch((error) => {
      // Failure code
      console.log(error);
    });
     
   } catch (error) {
     console.error('Error sending message:', error);
   }
 }
}


const readData = async () => {  
 if (selectedDevice && isConnected) {
    BleManager.read(
      selectedDevice.id,
      serviceid,
      caracid
    )
      .then((readData) => {
        // Success code
        console.log("Read: " + readData);
        const message = Buffer.from(readData);
        //const sensorData = buffer.readUInt8(1, true);
        if(receivedMessage.length>300){
          setReceivedMessage(""); //reset received message if length higher than 300
        }
        setReceivedMessage(receivedMessage => receivedMessage + message +"\n" );
        console.log("receivedMessage length",receivedMessage.length)
      })
      .catch((error) => {
        // Failure code
        console.log("Error reading message:",error);
      });
 }
}

 // disconnect from device
 const disconnectFromDevice = (device: Peripheral) => {
   BleManager.disconnect(device.id)
   .then(() => {
        setSelectedDevice(undefined);
        setIsConnected(false);
        setReceivedMessage("");
        clearInterval(intervalId);
        console.log("Disconnected from device");
   })
   .catch((error) => {
     // Failure code
     console.log("Error disconnecting:",error);
   });
 };

La función de representación en pantalla

Para la visualización, hemos decidido ponerlo todo en la misma pantalla. Habrá :

  • Un título
  • La liste des appareils qui n’apparait que si on n’est pas connecté (!isConnected &&)
  • Un encart type terminal de communication qui n’apparait que si on est connecté (selectedDevice && isConnected &&)
    • TextInput para escribir el mensaje a enviar messageToSend
    • Un botón de envío
    • Un botón de reproducción
    • Un cuadro de texto para mostrar receivedMessage
    • Un botón de desconexión
    return (
      <View>
      <Text
            style={{
              fontSize: 30,
              textAlign: 'center',
              borderBottomWidth: 1,
            }}>
            AC Bluetooth Terminal
          </Text>
        <ScrollView>

          {!isConnected && (
          <>
          {/*
          <Text>Available Devices:</Text>
          {devices.map((device) => (
            <Button
              key={device.id}
              title={device.name || 'Unnamed Device'}
              onPress={() => this.connectToDevice(device)}
            />
          ))}
          */}
          <Text>Paired Devices:</Text>
          {paired.map((pair: BluetoothDevice) => (
                      <View
                      style={{
                        flexDirection: 'row',
                        justifyContent: 'space-between',
                        marginBottom: 2,
                      }}>
                      <View style={styles.deviceItem}>
                        <Text style={styles.deviceName}>{pair.name}</Text>
                        <Text style={styles.deviceInfo}>{pair.id}</Text>
                      </View>
                      <TouchableOpacity
                        onPress={() =>
                          isConnected
                            ?  disconnect()
                            :  connectToDevice(pair)
                        }
                        style={styles.deviceButton}>
                        <Text
                          style={[
                            styles.scanButtonText,
                            {fontWeight: 'bold', fontSize: 12},
                          ]}>
                          {isConnected ? 'Disconnect' : 'Connect'}
                        </Text>
                      </TouchableOpacity>
                    </View>
          ))}
          </>  
          )}
          {selectedDevice && isConnected && (
            <>
              <View
                      style={{
                        flexDirection: 'row',
                        justifyContent: 'space-between',
                        margin: 5,
                      }}>
                      <View style={styles.deviceItem}>
                        <Text style={styles.deviceName}>{selectedDevice.name}</Text>
                        <Text style={styles.deviceInfo}>{selectedDevice.id}</Text>
                      </View>
                      <TouchableOpacity
                        onPress={() =>
                          isConnected
                            ?  disconnect()
                            :  connectToDevice(selectedDevice)
                        }
                        style={styles.deviceButton}>
                        <Text
                          style={styles.scanButtonText}>
                          {isConnected ? 'Disconnect' : 'Connect'}
                        </Text>
                      </TouchableOpacity>
                    </View>

          <View
              style={{
                flexDirection: 'row',
                justifyContent: 'space-between',
                margin: 5,
              }}>        
              <TextInput
                style={{
                  backgroundColor: '#888888',
                  margin: 2,
                  borderRadius: 15,
                  flex:3,
                  }}
                placeholder="Enter a message"
                value={messageToSend}
                onChangeText={(text) => setMessageToSend(text )}
              />
              <TouchableOpacity
                        onPress={() => sendMessage()
                        }
                        style={[styles.sendButton]}>
                        <Text
                          style={[
                            styles.scanButtonText,
                          ]}>
                          SEND
                        </Text>
                      </TouchableOpacity>
        </View>
              <Text>Received Message:</Text>
              <TextInput
              editable = {false}
              multiline
              numberOfLines={20}
              maxLength={100}
                style={{
                  backgroundColor: '#333333',
                  margin: 10,
                  borderRadius: 2,
                  borderWidth: 1,
                  borderColor: '#EEEEEE',
                  textAlignVertical: 'top',
                  }} >
                    {receivedMessage}
              </TextInput>
              
            </>
          )}
        </ScrollView>
      </View>
    );

Resultados

Como el emparejamiento no está gestionado por la aplicación, el ESP32 debe estar emparejado antes de utilizar la aplicación. Una vez que el código se ha cargado en el ESP32, puede iniciar la aplicación en el teléfono mediante el comando

npx react-native start

Código completo de la aplicación React Native

/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* https://github.com/innoveit/react-native-ble-manager
* https://blog.logrocket.com/using-react-native-ble-manager-mobile-app/
*/



import React, {useState, useEffect} from 'react';
import {   
  StyleSheet,
  Dimensions,
  View, 
  ScrollView, 
  Text,
  TextInput,
  PermissionsAndroid,
  TouchableOpacity,
  Platform} from 'react-native';
import BleManager,{Peripheral} from 'react-native-ble-manager';
import { Buffer } from 'buffer';

let serviceid="4fafc201-1fb5-459e-8fcc-c5c9c331914b";
let caracid="beb5483e-36e1-4688-b7f5-ea07361b26a8";

const BluetoothBLETerminal = () =&gt;  {
 const [devices, setDevices] = useState&lt;any[]&gt;([]);
 const [paired, setPaired] = useState&lt;any[]&gt;([]);
 const [selectedDevice, setSelectedDevice] = useState&lt;Peripheral&gt;();
 const [messageToSend, setMessageToSend] = useState("");
 const [receivedMessage, setReceivedMessage] = useState("");
 const [isConnected, setIsConnected] = useState(false);
 const [intervalId, setIntervalId] = useState&lt;NodeJS.Timer&gt;();
 const [isScanning, setIsScanning] = useState(false);

 const checkBluetoothEnabled = async () =&gt; {
   try {
         // turn on bluetooth if it is not on
   BleManager.enableBluetooth().then(() =&gt; {
     console.log('Bluetooth is turned on!');
   });
     
   } catch (error) {
     console.error('BLE is not available on this device.');
   }
 }
 
 const startScan = () =&gt; {
  if (!isScanning) {
    BleManager.scan([], 5, true)
      .then(() =&gt; {
        console.log('Scanning...');
        setIsScanning(true);
      })
      .catch(error =&gt; {
        console.error(error);
      });
  }
};

 const startDeviceDiscovery = async () =&gt; {

  BleManager.getBondedPeripherals().then((bondedPeripheralsArray) =&gt; {
    // Each peripheral in returned array will have id and name properties
    console.log("Bonded peripherals: " + bondedPeripheralsArray.length);
    setPaired(bondedPeripheralsArray);
  });

  /*BleManager.getDiscoveredPeripherals().then((peripheralsArray) =&gt; {
    // Success code
    console.log("Discovered peripherals: " + peripheralsArray.length);
  });*/
 }

 const connectToDevice = async (device: Peripheral) =&gt; {
 BleManager.connect(device.id)
     .then(() =&gt; {
     // Success code
     console.log("Connected");
     setSelectedDevice(device);
     setIsConnected(true);
     BleManager.retrieveServices(device.id).then(
       (deviceInfo) =&gt; {
       // Success code
       console.log("Device info:", deviceInfo);
       }
     );


     })
     .catch((error) =&gt; {
     // Failure code
     console.log(error);
     });
 }


const sendMessage = async () =&gt; {
 if(selectedDevice &amp;&amp; isConnected){
   try {

    const buffer = Buffer.from(messageToSend);
    BleManager.write(
      selectedDevice.id,
      serviceid,
      caracid,
      buffer.toJSON().data
    ).then(() =&gt; {
      // Success code
      console.log("Write: " + buffer.toJSON().data);
    })
    .catch((error) =&gt; {
      // Failure code
      console.log(error);
    });
     
   } catch (error) {
     console.error('Error sending message:', error);
   }
 }
}


const readData = async () =&gt; {  
 if (selectedDevice &amp;&amp; isConnected) {
    BleManager.read(
      selectedDevice.id,
      serviceid,
      caracid
    )
      .then((readData) =&gt; {
        // Success code
        console.log("Read: " + readData);
        const message = Buffer.from(readData);
        //const sensorData = buffer.readUInt8(1, true);
        if(receivedMessage.length&gt;300){
          setReceivedMessage("");
        }
        setReceivedMessage(receivedMessage =&gt; receivedMessage + message +"\n" );
        console.log("receivedMessage length",receivedMessage.length)
      })
      .catch((error) =&gt; {
        // Failure code
        console.log("Error reading message:",error);
      });
 }
}

/*useEffect(() =&gt; {
 let intervalId: string | number | NodeJS.Timer | undefined;
 if (selectedDevice &amp;&amp; isConnected) {
   intervalId = setInterval(() =&gt; readData(), 100);
   setIntervalId(intervalId);
 }
 return () =&gt; {
   clearInterval(intervalId);
 };
}, [isConnected,selectedDevice]);*/

 // disconnect from device
 const disconnectFromDevice = (device: Peripheral) =&gt; {
   BleManager.disconnect(device.id)
   .then(() =&gt; {
        setSelectedDevice(undefined);
        setIsConnected(false);
        setReceivedMessage("");
        clearInterval(intervalId);
        console.log("Disconnected from device");
   })
   .catch((error) =&gt; {
     // Failure code
     console.log("Error disconnecting:",error);
   });
   
   /*BleManager.removeBond(peripheral.id)
     .then(() =&gt; {
       peripheral.connected = false;
       peripherals.set(peripheral.id, peripheral);
       setConnectedDevices(Array.from(peripherals.values()));
       setDiscoveredDevices(Array.from(peripherals.values()));
       Alert.alert(`Disconnected from ${peripheral.name}`);
     })
     .catch(() =&gt; {
       console.log('fail to remove the bond');
     });*/



 };
 
 
 useEffect(() =&gt; {

    checkBluetoothEnabled();

    if (Platform.OS === 'android' &amp;&amp; Platform.Version &gt;= 23) {
  
        PermissionsAndroid.requestMultiple([
          PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
          PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
          PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
        ]).then(result =&gt; {
          if (
            (result['android.permission.BLUETOOTH_SCAN'] &amp;&amp;
            result['android.permission.BLUETOOTH_CONNECT'] &amp;&amp;
            result['android.permission.ACCESS_FINE_LOCATION'] === 'granted')
            ||
            (result['android.permission.BLUETOOTH_SCAN'] &amp;&amp;
            result['android.permission.BLUETOOTH_CONNECT'] &amp;&amp;
            result['android.permission.ACCESS_FINE_LOCATION'] === 'never_ask_again')
          ) {
            console.log('User accepted');
          } else {
            console.log('User refused');        }
        });

    }

    BleManager.start({showAlert: false}).then(() =&gt; {
      console.log('BleManager initialized');
      startDeviceDiscovery();
    }).catch((error) =&gt; {
      // Failure code
      console.log("Error requesting permission:",error);
    });
   
BleManager.checkState().then((state) =&gt;
   console.log(`current BLE state = '${state}'.`)
 );

 BleManager.getConnectedPeripherals([]).then((peripheralsArray) =&gt; {
   // Success code
   console.log("Connected peripherals: " + peripheralsArray.length);
 });

 BleManager.getBondedPeripherals().then((bondedPeripheralsArray) =&gt; {
   // Each peripheral in returned array will have id and name properties
   console.log("Bonded peripherals: " + bondedPeripheralsArray.length);
   //setBoundedDevices(bondedPeripheralsArray);
 });

 BleManager.getDiscoveredPeripherals().then((peripheralsArray) =&gt; {
   // Success code
   console.log("Discovered peripherals: " + peripheralsArray.length);
 });

 /*let stopDiscoverListener = BleManagerEmitter.addListener(
   'BleManagerDiscoverPeripheral',
   peripheral =&gt; {
     peripherals.set(peripheral.id, peripheral);
   },
 );*/

 /*let stopConnectListener = BleManagerEmitter.addListener(
   'BleManagerConnectPeripheral',
   peripheral =&gt; {
     console.log('BleManagerConnectPeripheral:', peripheral);
     peripherals.set(peripheral.id, peripheral);
     setConnectedDevices(Array.from(peripherals.values()));
   },
 );*/

 /*let stopScanListener = BleManagerEmitter.addListener(
   'BleManagerStopScan',
   () =&gt; {
     setIsScanning(false);
     console.log('scan stopped');
     BleManager.getDiscoveredPeripherals().then((peripheralsArray) =&gt; {
       // Success code
       console.log("Discovered peripherals: " + peripheralsArray.length);
       for (let i = 0; i &lt; peripheralsArray.length; i++) {
         let peripheral = peripheralsArray[i];
         console.log("item:", peripheral);
         //peripheral.connected = true;
         peripherals.set(peripheral.id, peripheral);
         setDiscoveredDevices(peripheralsArray);
       }

       
     });
   },
 );*/

 return () =&gt; {
   /*stopDiscoverListener.remove();
   stopConnectListener.remove();
   stopScanListener.remove();*/
 };
 }, [])


   return (
     &lt;View style={[styles.mainBody]}&gt;
     &lt;Text
           style={{
             fontSize: 30,
             textAlign: 'center',
             borderBottomWidth: 1,
           }}&gt;
           AC BLE Terminal
         &lt;/Text&gt;
       &lt;ScrollView&gt;

         {!isConnected &amp;&amp; (
         &lt;&gt;

        &lt;TouchableOpacity
                       onPress={() =&gt; startDeviceDiscovery()
                       }
                       style={[styles.deviceButton]}&gt;
                       &lt;Text
                         style={[
                           styles.scanButtonText,
                         ]}&gt;
                         SCAN
                       &lt;/Text&gt;
              &lt;/TouchableOpacity&gt;

         {/*
         &lt;Text&gt;Available Devices:&lt;/Text&gt;
         {devices.map((device) =&gt; (
           &lt;Button
             key={device.id}
             title={device.name || 'Unnamed Device'}
             onPress={() =&gt; this.connectToDevice(device)}
           /&gt;
         ))}
         */}
         &lt;Text&gt;Paired Devices:&lt;/Text&gt;
         {paired.map((pair,i) =&gt; (
                     &lt;View key={i}
                     style={{
                       flexDirection: 'row',
                       justifyContent: 'space-between',
                       marginBottom: 2,
                     }}&gt;
                     &lt;View style={styles.deviceItem}&gt;
                       &lt;Text style={styles.deviceName}&gt;{pair.name}&lt;/Text&gt;
                       &lt;Text style={styles.deviceInfo}&gt;{pair.id}, rssi: {pair.rssi}&lt;/Text&gt;
                     &lt;/View&gt;
                     &lt;TouchableOpacity
                       onPress={() =&gt;
                         isConnected
                           ?  disconnectFromDevice(pair)
                           :  connectToDevice(pair)
                       }
                       style={styles.deviceButton}&gt;
                       &lt;Text
                         style={[
                           styles.scanButtonText,
                           {fontWeight: 'bold', fontSize: 12},
                         ]}&gt;
                         {isConnected ? 'Disconnect' : 'Connect'}
                       &lt;/Text&gt;
                     &lt;/TouchableOpacity&gt;
                   &lt;/View&gt;
         ))}
         &lt;/&gt;  
         )}
         {selectedDevice &amp;&amp; isConnected &amp;&amp; (
           &lt;&gt;
             &lt;View
                     style={{
                       flexDirection: 'row',
                       justifyContent: 'space-between',
                       margin: 5,
                     }}&gt;
                     &lt;View style={styles.deviceItem}&gt;
                       &lt;Text style={styles.deviceName}&gt;{selectedDevice.name}&lt;/Text&gt;
                       &lt;Text style={styles.deviceInfo}&gt;{selectedDevice.id}, rssi: {selectedDevice.rssi}&lt;/Text&gt;
                     &lt;/View&gt;
                     &lt;TouchableOpacity
                       onPress={() =&gt;
                         isConnected
                           ?  disconnectFromDevice(selectedDevice)
                           :  connectToDevice(selectedDevice)
                       }
                       style={styles.deviceButton}&gt;
                       &lt;Text
                         style={styles.scanButtonText}&gt;
                         {isConnected ? 'Disconnect' : 'Connect'}
                       &lt;/Text&gt;
                     &lt;/TouchableOpacity&gt;
                   &lt;/View&gt;

         &lt;View
             style={{
               flexDirection: 'row',
               justifyContent: 'space-between',
               margin: 5,
             }}&gt;        
             &lt;TextInput
               style={{
                 backgroundColor: '#888888',
                 margin: 2,
                 borderRadius: 15,
                 flex:3,
                 }}
               placeholder="Enter a message"
               value={messageToSend}
               onChangeText={(text) =&gt; setMessageToSend(text)}
             /&gt;
             &lt;TouchableOpacity
                       onPress={() =&gt; sendMessage()
                       }
                       style={[styles.sendButton]}&gt;
                       &lt;Text
                         style={[
                           styles.scanButtonText,
                         ]}&gt;
                         SEND
                       &lt;/Text&gt;
                     &lt;/TouchableOpacity&gt;
       &lt;/View&gt;
       &lt;View
             style={{
               flexDirection: 'row',
               justifyContent: 'space-between',
               margin: 5,
             }}&gt;
             &lt;Text style={{textAlignVertical: 'center'}}&gt;Received Message:&lt;/Text&gt;
             &lt;TouchableOpacity
                       onPress={() =&gt; readData()
                       }
                       style={[styles.deviceButton]}&gt;
                       &lt;Text
                         style={[
                           styles.scanButtonText,
                         ]}&gt;
                         READ
                       &lt;/Text&gt;
              &lt;/TouchableOpacity&gt;
        &lt;/View&gt;
             &lt;TextInput
             editable = {false}
             multiline
             numberOfLines={20}
             maxLength={300}
               style={{
                 backgroundColor: '#333333',
                 margin: 10,
                 borderRadius: 2,
                 borderWidth: 1,
                 borderColor: '#EEEEEE',
                 textAlignVertical: 'top',
                 }} &gt;
                   {receivedMessage}
             &lt;/TextInput&gt;
             
           &lt;/&gt;
         )}
       &lt;/ScrollView&gt;
     &lt;/View&gt;
   );

};//end of component

//https://medium.com/supercharges-mobile-product-guide/reactive-styles-in-react-native-79a41fbdc404
export const theme = {
  smallPhone: 0,
  phone: 290,
  tablet: 750,
  }

const windowHeight = Dimensions.get('window').height;
const styles = StyleSheet.create({
 mainBody: {
   flex: 1,
   justifyContent: 'center',
   height: windowHeight,

   ...Platform.select ({
    ios: {
      fontFamily: "Arial",
    },
    
    android: {
      fontFamily: "Roboto",

    },
  }),
 },

 scanButtonText: {
   color: 'white',
   fontWeight: 'bold',
   fontSize: 12,
   textAlign: 'center',
 },
 noDevicesText: {
   textAlign: 'center',
   marginTop: 10,
   fontStyle: 'italic',
 },
 deviceItem: {
   marginBottom: 2,
 },
 deviceName: {
   fontSize: 14,
   fontWeight: 'bold',
 },
 deviceInfo: {
   fontSize: 8,
 },
 deviceButton: {
   backgroundColor: '#2196F3',
   padding: 10,
   borderRadius: 10,
   margin: 2,
   paddingHorizontal: 20,
 },
 sendButton: {
  backgroundColor: '#2196F3',
  padding: 15,
  borderRadius: 15,
  margin: 2,
  paddingHorizontal: 20,
 },
});

export default BluetoothBLETerminal;

Fuentes

¿De cuánta utilidad te ha parecido este contenido?

¡Haz clic en una estrella para puntuarlo!

Promedio de puntuación 0 / 5. Recuento de votos: 0

Hasta ahora, ¡no hay votos!. Sé el primero en puntuar este contenido.

Ya que has encontrado útil este contenido...

¡Sígueme en los medios sociales!

¡Siento que este contenido no te haya sido útil!

¡Déjame mejorar este contenido!

Dime, ¿cómo puedo mejorar este contenido?