MadMax
MadMax

Reputation: 101

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?

Upvotes: 4

Views: 8945

Answers (2)

Maxim Firsoff
Maxim Firsoff

Reputation: 2296

I think the best way is starting at this article - making-android-ble-work-part.

There are lots of reasons why your data doesn't pass to the device:

  1. devices firmware (check it using nRF Connect app)
  2. logical mistakes in the Android code (loot at the article to try fix them)

Upvotes: 0

Youssif Saeed
Youssif Saeed

Reputation: 13295

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:-

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:-

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

Upvotes: 11

Related Questions