0

I want to have a button on raspberry pi to send a message to android device using bluetooth,is it possible by using the raspberry pi or i should look for another iot hardware ?

  • 1
    The Pi 3 would be ideal as it has on-board Bluetooth. There are also lots of tutorials based around the Raspberry Pi, so with a bit of research I'm sure you will find what you need. – Darth Vader Aug 14 '17 at 8:21
  • You even have a choice to use standard Bluetooth or Bluetooth Low Energy! I have successfully done BLE from Pi to Android and iOS apps. – Quintin Balsdon Aug 14 '17 at 8:48
1

So I have achieved this by creating a Raspberry Pi Bluetooth Low Energy Peripheral device. The code is on Github for the Raspberry Pi peripheral and for the accompanying Android app. Just make sure your raspberry pi is up to date.

Raspberry Pi Bluetooth Ble Peripheral with Bleno:

var bleno = require('bleno');
var exec = require('child_process').exec;

var CHUNK_SIZE = 20;

var Descriptor = bleno.Descriptor;

var deviceName = 'RaspberrPi3';
var myId = '4afb720a-5214-4337-841b-d5f954214877';
var data = new Buffer('Send me some data to display');
var output = "";
var updateCallback;

var terminalCallback;
var terminalResponse;

var START_CHAR = String.fromCharCode(002); //START OF TEXT CHAR
var END_CHAR = String.fromCharCode(003);   //END OF TEXT CHAR

function sliceUpResponse(callback, responseText) {
  if (!responseText || !responseText.trim()) return;
  callback(new Buffer(START_CHAR));
  while(responseText !== '') {
      callback(new Buffer(responseText.substring(0, CHUNK_SIZE)));
      responseText = responseText.substring(CHUNK_SIZE);
  }
  callback(new Buffer(END_CHAR));
}

var terminal = new bleno.Characteristic({
    uuid : '8bacc104-15eb-4b37-bea6-0df3ac364199',
    properties : ['write','read','notify'],
    onReadRequest : function(offset, callback) {
        console.log("Read request");
        callback(bleno.Characteristic.RESULT_SUCCESS, new Buffer(terminalResponse).slice(offset));
    },
    onWriteRequest : function(newData, offset, withoutResponse, callback) {
        if(offset) {
            callback(bleno.Characteristic.RESULT_ATTR_NOT_LONG);
        } else {
            var data = newData.toString('utf8');
            console.log("Command received: [" + data + "]");
            dir = exec(data, function(err, stdout, stderr) {
                if (err) {
                    var stringError = JSON.stringify(err);
                    console.log(stringError);
                    callback(bleno.Characteristic.RESULT_SUCCESS);
                    terminalResponse = stringError;
                } else {
                    console.log(stdout);
                    callback(bleno.Characteristic.RESULT_SUCCESS);
                    terminalResponse = stdout;
                }
                if (terminalCallback) sliceUpResponse(terminalCallback, terminalResponse);
            });
        }
    },
    onSubscribe: function(maxValueSize, updateValueCallback) {
       console.log("onSubscribe called");
       terminalCallback = updateValueCallback;
    },
    onUnsubscribe: function() {
        terminalCallback = null;
        console.log("onUnsubscribe");
    }
});

bleno.on('stateChange', function(state) {
    console.log('on -> stateChange: ' + state);
    if (state === 'poweredOn') {
        bleno.startAdvertising(deviceName,[myId]);
    } else {
        bleno.stopAdvertising();
    }
});

bleno.on('advertisingStart', function(error) {
    console.log('on -> advertisingStart: ' + (error ? 'error ' + error : 'success'));
    if (!error) {
        bleno.setServices([
            new bleno.PrimaryService({
                uuid : myId,
                characteristics : [
                    // add characteristics here
                    terminal
                ]
            })
        ]);
        console.log('service added');
    }
});

bleno.on('accept', function(clientAddress) {
    console.log("Accepted connection from: " + clientAddress);
});

bleno.on('disconnect', function(clientAddress) {
    console.log("Disconnected from: " + clientAddress);
});   

Android class for connecting to a Bluetooth Low Energy device:

public class BLEPeripheral {

  private String mDeviceId;
  private BLEManager mConnector;
  private BluetoothAdapter mBluetoothAdapter;
  private BluetoothLeScanner mBLEScanner;
  private BluetoothGatt mBluetoothGatt;
  private BluetoothGattService mService = null;
  private HashMap<String, Command<String>> subscriptions;

  public BLEPeripheral(BLEManager connector, String deviceId) {
      mConnector = connector;
      mDeviceId = deviceId;

      mConnector.onDisconnected();
      final BluetoothManager bluetoothManager = (BluetoothManager) mConnector.getContext().getSystemService(Context.BLUETOOTH_SERVICE);
      mBluetoothAdapter = bluetoothManager.getAdapter();

      if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
          mConnector.enableBluetooth();
          return;
      }

      if (!mConnector.checkPermission()) return;

      scanForDevice();
  }

  public void scanForDevice() {
      mConnector.log("BT ENABLED: SCANNING FOR DEVICES");
      mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
      mBLEScanner.startScan(mLEScanCallback);
  }

  public void stopScan() {
      mBLEScanner.stopScan(mLEScanCallback);
  }

  private ScanCallback mLEScanCallback = new ScanCallback() {
      @Override
      public void onScanResult(int callbackType, ScanResult result) {
          BluetoothDevice device = result.getDevice();
          ScanRecord record = result.getScanRecord();
          if (record == null) {
              mConnector.log(String.format("Device [%s] has no scan record", device.getAddress()));
              return;
          }

          String name = record.getDeviceName();
          String UUID = null;

          if (record.getServiceUuids() != null) {
              for (ParcelUuid pId : record.getServiceUuids()) {
                  if (pId.getUuid().toString().equals(mDeviceId)) {
                      UUID = pId.getUuid().toString();
                  }
              }
          }
          if (UUID == null) {
              mConnector.log(String.format("Discovered Device [%s]. Continuing search", name));
              return;
          }
          mConnector.log(String.format("Peripheral [%s] located on Device [%s]. Attempting connection", UUID, name));
          mBluetoothGatt = device.connectGatt(mConnector.getContext(), true, mGattCallback);
          stopScan();
          super.onScanResult(callbackType, result);
      }
  };

  private void closeGatt() {
      mConnector.onDisconnected();
      if (mBluetoothGatt == null) {
          return;
      }
      mBluetoothGatt.close();
      mBluetoothGatt = null;
      scanForDevice();
  }

  private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
      StringBuilder buffer;
              @Override
              public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                  mConnector.onConnectionStateChange(newState);
                  if (newState == BluetoothProfile.STATE_CONNECTED) {
                      mConnector.log("Connected to device GATT. Discovering services");
                      mBluetoothGatt.discoverServices();
                  } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                      mConnector.log("Disconnected from GATT server. Continuing scanning");
                      closeGatt();
                  }
              }

              @Override
              public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                  if (status == BluetoothGatt.GATT_SUCCESS) {
                      if (mBluetoothGatt.getServices() != null) {
                          for (BluetoothGattService service : mBluetoothGatt.getServices()) {
                              if (service.getUuid().toString().equals(mDeviceId)) {
                                  mService = service;
                                  mConnector.onConnected();
                                  mConnector.log("Service discovered");
                              }
                          }
                      }

                  } else {
                      mConnector.log(String.format("onServicesDiscovered received: [%s]", status));
                  }
              }

              @Override
              public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                  if (status == BluetoothGatt.GATT_SUCCESS) {
                      mConnector.log(String.format("onCharacteristicRead received: [%s] value: [%s]", characteristic.getUuid().toString(), new String(characteristic.getValue())));
                  } else {
                      mConnector.log(String.format("onCharacteristicRead fail received: [%s]", status));
                  }
              }

              @Override
              public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                  super.onCharacteristicWrite(gatt, characteristic, status);
                  if (status == BluetoothGatt.GATT_SUCCESS) {
                      mConnector.log(String.format("onCharacteristicWrite received: [%s] value: [%s]", characteristic.getUuid().toString(), new String(characteristic.getValue())));
                  }
              }

              @Override
              public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                  String packet = new String(characteristic.getValue());
                  if (packet.equals(String.valueOf((char)2))) {
                      buffer = new StringBuilder();
                  } else if (packet.equals(String.valueOf((char)3))) {
                      //mConnector.log(String.format("Characteristic received: [%s] Value: [%s]", characteristic.getUuid().toString(), buffer.toString()));
                      if (subscriptions == null || subscriptions.size() == 0) return;

                      Command<String> handler = subscriptions.get(characteristic.getUuid().toString());
                      if (handler != null) handler.execute(new String(buffer.toString()));
                  } else {
                      buffer.append(packet);
                  }
              }
          };

  public BluetoothGattService getService() {
      return mService;
  }

  private BluetoothGattCharacteristic findCharacteristicById(String id) {
      if (mService.getCharacteristics() != null) {
          return mService.getCharacteristic(java.util.UUID.fromString(id));
      }
      return null;
  }

  public void subscribe(String characteristicId, Command<String> handler){
      if (subscriptions == null) subscriptions = new HashMap<>();
      BluetoothGattCharacteristic characteristic = findCharacteristicById(characteristicId);

      if (characteristic == null) {
          mConnector.log("Characteristic does not exist");
          return;
      }

      mBluetoothGatt.setCharacteristicNotification(characteristic, true);
      BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
      descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
      mBluetoothGatt.writeDescriptor(descriptor);

      subscriptions.put(characteristicId, handler);
  }

  public void writeCharacteristic(String characteristicId, String data) {
      BluetoothGattCharacteristic characteristic = findCharacteristicById(characteristicId);
      if (characteristic != null) {
          characteristic.setValue(data);
          mBluetoothGatt.writeCharacteristic(characteristic);
          mConnector.log(String.format("Wrote [%s] to [%s]", data, characteristicId));
      } else {
          mConnector.log(String.format("[%s] not found on device", characteristicId));
      }
  }

  public void readCharacteristic(String characteristicId) {
      BluetoothGattCharacteristic characteristic = findCharacteristicById(characteristicId);
      if (characteristic == null) return;
      mBluetoothGatt.readCharacteristic(characteristic);
  }
}
| improve this answer | |
  • Thank you so much Quintin, i am a beginner so i don't know what a 'ble' is and how to make it work with raspberry pi ?? – Shubham Verma Aug 15 '17 at 8:43
  • and should i purchase Raspberry pi 3 ? – Shubham Verma Aug 15 '17 at 8:45
  • BLE stands for Bluetooth Low Energy. Raspberry Pi 0 W (raspberrypi.org/products/raspberry-pi-zero-w) and Raspberry Pi 3 (raspberrypi.org/products/raspberry-pi-3-model-b) boards come with the required hardware built in. BLE (en.wikipedia.org/wiki/Bluetooth_Low_Energy) is the technology of choice for smartwatches and other personal devices that interact with smart phone – Quintin Balsdon Aug 15 '17 at 8:51
  • Do I need to purchase another component for ble along with raspberry pi ? – Shubham Verma Aug 16 '17 at 10:15
  • Not if you order one of the boards I gave links to in the comments above - the 3 model B or the Pi 0 W. Since I am not sure where you are from you would need to find a supplier that you can order from. If you are satisfied with my answer, please mark it as the answer (Green tick near the top of my answer). – Quintin Balsdon Aug 16 '17 at 10:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.