Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android + ESP32 send data over bluetooth (BLE)

I'm trying to send data from my android app to an esp32 over bluetooth (BLE) but i can't find the proper way to do it. All i can do for now is scan and find ble devices. My arduino code is working as i want (it receives the data properly) because i used another app which let me send data to ble devices so i know the arduino code is fine.

I've been searching for days here and google how to achieve it but i still stucked in it. This is my code for now:

Scanner:

class BluetoothFragment : Fragment() {
    private lateinit var binding: FragmentBluetoothBinding
    private var list : MutableList<BluetoothDevice> = ArrayList()
    private lateinit var  bluetoothAdapter : BluetoothAdapter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        Log.d("DeviceListActivity", "onCreate()")
        return inflater.inflate(R.layout.fragment_bluetooth, container, false)
    }

    // TODO: 19/05/2021 implementar listener en el recycler view para crear la conexión con el ble

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding = FragmentBluetoothBinding.bind(view)
        if (ContextCompat.checkSelfPermission(
                requireContext(),
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            val permissions = arrayOf(
                android.Manifest.permission.ACCESS_COARSE_LOCATION,
            )
            ActivityCompat.requestPermissions(requireActivity(), permissions, 0)
        }

        setRecyclerView(list)
    }

    private val bleScanner = object :ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult?) {
            super.onScanResult(callbackType, result)
            Log.d("pepe","onScanResult: ${result?.device?.address} - ${result?.device?.name}")
            if(result?.device?.name?.isNotEmpty() == true){
                var bluetoothDevice = result?.device?.name?.let { BluetoothDevice(it) }
                if (bluetoothDevice != null) {
                    list.add(bluetoothDevice)
                    bluetoothAdapter.notifyDataSetChanged()
                }
            }
        }

        override fun onBatchScanResults(results: MutableList<ScanResult>?) {
            super.onBatchScanResults(results)
            Log.d("DeviceListActivity","onBatchScanResults:${results.toString()}")
        }

        override fun onScanFailed(errorCode: Int) {
            super.onScanFailed(errorCode)
            Log.d("DeviceListActivity", "onScanFailed: $errorCode")
        }

    }

    private val bluetoothLeScanner: BluetoothLeScanner
        get() {
            val bluetoothManager = requireActivity().getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
            val bluetoothAdapter = bluetoothManager.adapter
            return bluetoothAdapter.bluetoothLeScanner
        }

    class ListDevicesAdapter(context: Context?, resource: Int) : ArrayAdapter<String>(context!!, resource)


    override fun onStart() {
        Log.d("DeviceListActivity","onStart()")
        super.onStart()
        bluetoothLeScanner.startScan(bleScanner)
    }

    override fun onStop() {
        bluetoothLeScanner.stopScan(bleScanner)
        super.onStop()
    }

    private fun setRecyclerView(allCategories: List<BluetoothDevice>) {
        val layoutManager: RecyclerView.LayoutManager = LinearLayoutManager(context)
        binding.rvBluetooth.layoutManager = layoutManager
        bluetoothAdapter = BluetoothAdapter(allCategories)
        binding.rvBluetooth.adapter = bluetoothAdapter
    }
}

Arduino code (I'm controlling a little car with it so thats why i have 5 different values):

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

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

// Motor 1
int motor1Pin1 = 23;
int motor1Pin2 = 22;
int enable1Pin = 21;

// Motor 2
int motor2Pin1 = 18;
int motor2Pin2 = 19;
int enable2Pin = 5;

const int freq = 30000;
const int pwmChannel = 0;
const int resolution = 8;
int dutyCycle = 200;

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

      if (value.length() > 0) {
        if (value[0] == '1') {
          dutyCycle = 200;
          Serial.println("Moving Forward");
          digitalWrite(motor1Pin1, LOW);
          digitalWrite(motor1Pin2, HIGH);
          digitalWrite(motor2Pin1, LOW);
          digitalWrite(motor2Pin2, HIGH);
          while (dutyCycle <= 255) {
            ledcWrite(pwmChannel, dutyCycle);
            dutyCycle = dutyCycle + 5;
            delay(500);
          }

        }
        if (value[0] == '4') {
          dutyCycle = 200;
          Serial.println("Moving Backwards");
          digitalWrite(motor1Pin1, HIGH);
          digitalWrite(motor1Pin2, LOW);
          digitalWrite(motor2Pin1, HIGH);
          digitalWrite(motor2Pin2, LOW);
          while (dutyCycle <= 255) {
            ledcWrite(pwmChannel, dutyCycle);
            dutyCycle = dutyCycle + 5;
            delay(500);
          }
        }
        if (value[0] == '2') {
          dutyCycle = 100;
          Serial.println("Motor right");
          digitalWrite(motor1Pin1, LOW);
          digitalWrite(motor1Pin2, HIGH);
          digitalWrite(motor2Pin1, HIGH);
          digitalWrite(motor2Pin2, LOW);
        }
        if (value[0] == '3') {
          dutyCycle = 100;
          Serial.println("Motor left");
          digitalWrite(motor1Pin1, HIGH);
          digitalWrite(motor1Pin2, LOW);
          digitalWrite(motor2Pin1, LOW);
          digitalWrite(motor2Pin2, HIGH);
        }
        if (value[0] == '0') {
          Serial.println("Motor stopped");
          digitalWrite(motor1Pin1, LOW);
          digitalWrite(motor1Pin2, LOW);
          digitalWrite(motor2Pin1, LOW);
          digitalWrite(motor2Pin2, LOW);
        }
      }
    }
};


void setup() {
  Serial.begin(115200);
  BLEDevice::init("Andruino");
  BLEServer *pServer = BLEDevice::createServer();

  BLEService *pService = pServer->createService(SERVICE_UUID);

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

  pCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();

  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  pinMode(enable1Pin, OUTPUT);

  pinMode(motor2Pin1, OUTPUT);
  pinMode(motor2Pin2, OUTPUT);
  pinMode(enable2Pin, OUTPUT);

  ledcSetup(pwmChannel, freq, resolution);

  ledcAttachPin(enable1Pin, pwmChannel);
  ledcAttachPin(enable2Pin, pwmChannel);
 
  ledcWrite(pwmChannel, dutyCycle);
}

void loop() {

}

How could i send data from my android app to esp32 over bluetooth?

like image 339
MadMax Avatar asked Oct 26 '25 07:10

MadMax


1 Answers

In order to get this working, I would do the following if I was you:-

Part A: Get this working with an existing Android app (e.g. nRF Connect - maybe you've already done this part)

  1. Download and install nRF Connect app from the play store.
  2. Launch nRF Connect app and scan for devices.
  3. Connect to your ESP32 if it was found.
  4. Browse the GATT table and find the UUID and handle of the characteristic that controls the ESP32. This is important as it will be used in Part B.
  5. Once found, try to write the values 0, 1, 2, 3, and 4 to this characteristic and ensure that everything is working.

If there are parts above that are new to you, please have a look at the links below. If you've already successfully done all of the above, then move to Part B:-

  • nRF Connect For Mobile - Get Started
  • Bluetooth Low Energy Characteristics - A Beginner's Guide
  • Introduction to BLE - GATT

Part B: Get this working using your Android app:-

  1. Similar to the nRF Connect app, your app needs to scan and connect to the ESP32. You can find examples on how to do this here.
  2. Once you are connected, you need to browse the GATT Table and find the right characteristic. You can find examples for this here.
  3. Once you find the right characteristic and its handle (this is the one you noted in step 4 above), proceed to write values to this characteristic. You can find examples here, here and here.

If all of this is in place and it is still not working, here are things to check:-

  • Are you waiting for the GATT write completion callback? Also check this.
  • Are you using the right Android write operation?
  • Are you maybe using reliable writes instead of normal write?
  • Are you sending integer data instead of string data? The app expects integer data in order to work properly.

You can find examples and explanations about the steps above in the links below:-

  • How to Send Data over a BLE Link
  • Use BLE to connect to devices in an Android app
  • The Ultimate Guide to Android BLE Development
  • Getting Started with Bluetooth Low Energy on Android
  • How to Use Android BLE to Communicate with Devices
like image 115
Youssif Saeed Avatar answered Oct 29 '25 07:10

Youssif Saeed



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!