android bleiot

Installation

android studio

Download Android Studio

  • Le test du bluetooth doit se faire obligatoirement avec un smartphone.
  • Sous linux, il est nécessaire de mettre à jour les règles d’utilisation d’un composant USB :
$ wget http://web.enib.fr/~kerhoas/INSTALL_/51-android.rules.zip
$ unzip 51-android.rules.zip
$ cp 51-android.rules /etc/udev/rules.d/

Screenshot_android.png


Application BLEIOT

Projet Source

BleIot_enib_android.zip

BleIotActivity.java
package fr.enib.bleiot_android;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

//==================================================================================================
public class BleIotActivity extends Activity {

    private static final String TAG = "BleIotActivity";
    private static TextView ledState;
    AlertDialog mSelectionDialog;
    DevicesAdapter mDevicesAdapter;
    BluetoothAdapter mBluetoothAdapter;
    BluetoothLeScanner mBluetoothLeScanner;
    private BluetoothLeScanner mLEScanner;
    private ScanSettings settings;
    Handler mHandler;
    boolean mScanning;
    BluetoothGatt mGatt;
    BluetoothGatt mWriteCharac;
    private static final int REQUEST_ENABLE_BT = 1;
    public static BluetoothGattCharacteristic mWriteCharacteristic;
    private Queue<BluetoothGattDescriptor> descriptorWriteQueue = new LinkedList<>();
    private static final int SCAN_PERIOD = 10000;

    //##############
    final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;


    //==================================================================================================
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mHandler = new Handler();
        mDevicesAdapter = new DevicesAdapter(getLayoutInflater());

        if (Build.VERSION.SDK_INT >= 23) {
            // Marshmallow+ Permission APIs
            permMarshMallow();
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.select_device);
        builder.setAdapter(mDevicesAdapter, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                finishScanning();
                BluetoothDevice device = (BluetoothDevice) mDevicesAdapter.getItem(i);
                if (device != null) {
                    Log.i(TAG, "Connecting to GATT server at: " + device.getAddress());
                    mGatt = device.connectGatt(BleIotActivity.this, false, mGattCallback);
                }
            }
        });
        builder.setNegativeButton(R.string.cancel, null);
        builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialogInterface) {
                finishScanning();
            }
        });
        mSelectionDialog = builder.create();

        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();

        mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
        settings = new ScanSettings.Builder()
                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                .build();

        setContentView(R.layout.activity_bleiot);
    }
//==================================================================================================
//                      ALLOW PERMISSIONS
//==================================================================================================
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: {
                Map<String, Integer> perms = new HashMap<String, Integer>();
                // Initial
                perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
                // Fill with results
                for (int i = 0; i < permissions.length; i++)
                    perms.put(permissions[i], grantResults[i]);
                // Check for ACCESS_FINE_LOCATION
                if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED

                ) {
                    // All Permissions Granted
                    // Permission Denied
                    Toast.makeText(BleIotActivity.this, "All Permission GRANTED !! Thank You :)", Toast.LENGTH_SHORT)
                            .show();
                } else {
                    // Permission Denied
                    Toast.makeText(BleIotActivity.this, "One or More Permissions are DENIED Exiting App :(", Toast.LENGTH_SHORT)
                            .show();
                    finish();
                }
            }
            break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    @TargetApi(Build.VERSION_CODES.M)
    private void permMarshMallow() {
        List<String> permissionsNeeded = new ArrayList<String>();

        final List<String> permissionsList = new ArrayList<String>();
        if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
            permissionsNeeded.add("Show Location");

        if (permissionsList.size() > 0) {
            if (permissionsNeeded.size() > 0) {

                // Need Rationale
                String message = "App need access to " + permissionsNeeded.get(0);
                for (int i = 1; i < permissionsNeeded.size(); i++)
                    message = message + ", " + permissionsNeeded.get(i);
                showMessageOKCancel(message,
                        new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                                        REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                            }
                        });
                return;
            }
            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
            return;
        }

        Toast.makeText(BleIotActivity.this, "No new Permission Required- Launching App .", Toast.LENGTH_SHORT)
                .show();
    }

    private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(BleIotActivity.this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", null)
                .create()
                .show();
    }

    @TargetApi(Build.VERSION_CODES.M)
    private boolean addPermission(List<String> permissionsList, String permission) {

        if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
            permissionsList.add(permission);
            // Check for Rationale Option
            if (!shouldShowRequestPermissionRationale(permission))
                return false;
        }
        return true;
    }
//==================================================================================================
//                      SWITCH LED BUTTON
//==================================================================================================

    public void onSwitchLedClick(View view) {

        BluetoothGattCharacteristic charac = null;
        List<BluetoothGattService> gattServices = getSupportedGattServices();

        if (gattServices == null) {
            Log.w(TAG, "Not services found.");
            return;
        }

        for (BluetoothGattService gattService : gattServices) {
            List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
            for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                if (gattCharacteristic.getUuid().equals(AssignedNumber.getBleUuid("switch led"))) {
                    charac = gattCharacteristic;
                }
            }
        }

        if (charac == null) {
            Log.e(TAG, "char not found!");
            return;
        }

        byte[] value = new byte[1];
        value[0] = (byte) (21 & 0xFF);
        charac.setValue(value);
        boolean status = mGatt.writeCharacteristic(charac);
        return ;
    }

    //==================================================================================================
    public void onConnectClick(View view) {
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        } else {
            String btnText = ((Button) view).getText().toString();
            if (btnText.equals(getString(R.string.connect))) {
                openSelectionDialog();
            } else if (btnText.equals(getString(R.string.disconnect))) {
                mGatt.disconnect();
                mGatt.close();
                updateConnectButton(BluetoothProfile.STATE_DISCONNECTED);
            }
        }
    }
    //==================================================================================================
    void openSelectionDialog() {
        beginScanning();
        mSelectionDialog.show();
    }
    //==================================================================================================
    private void beginScanning() {
        if (!mScanning) {


            mDevicesAdapter.clear();
            mDevicesAdapter.add(null);
            mDevicesAdapter.updateScanningState(mScanning = true);
            mDevicesAdapter.notifyDataSetChanged();

            mLEScanner.startScan(mScanCallback);


            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    finishScanning();
                }
            }, SCAN_PERIOD);

        }
    }
    //==================================================================================================
    private void finishScanning() {
        if (mScanning) {
            if (mDevicesAdapter.getItem(0) == null) {
                mDevicesAdapter.notifyDataSetChanged();
            }

        }
        else {  mLEScanner.stopScan(mScanCallback); }


    }
    //==================================================================================================
    private void disconnect() {
        if (mGatt != null) {
            mGatt.disconnect();
            mGatt.close();
            mGatt = null;
        }
    }
    //==================================================================================================
    @Override
    protected void onPause() {
        super.onPause();
        finishScanning();
    }
    //==================================================================================================
    @Override
    protected void onDestroy() {
        super.onDestroy();
        disconnect();
    }
    //==================================================================================================
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_ENABLE_BT) {
            if (resultCode == Activity.RESULT_OK) {
                openSelectionDialog();
            } else if (resultCode == Activity.RESULT_CANCELED) {
                Toast.makeText(this, "App cannot run with bluetooth off", Toast.LENGTH_LONG).show();
                finish();
            }
        } else
            super.onActivityResult(requestCode, resultCode, data);
    }

    //==================================================================================================
    private void updateConnectButton(int state) {
        Button connectBtn = (Button) BleIotActivity.this.findViewById(R.id.connect_button);
        switch (state) {
            case BluetoothProfile.STATE_DISCONNECTED:
                connectBtn.setText(getString(R.string.connect));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        TextView pressionTxt = (TextView) BleIotActivity.this.findViewById(R.id.Pvalue);
                        pressionTxt.setText("--");
                        TextView temperatureTxt = (TextView)BleIotActivity.this.findViewById(R.id.Tvalue);
                        temperatureTxt.setText(R.string.Tvalue);
                    }
                });
                break;
            case BluetoothProfile.STATE_CONNECTING:
                connectBtn.setText(getString(R.string.connecting));
                break;
            case BluetoothProfile.STATE_CONNECTED:
                connectBtn.setText(getString(R.string.disconnect));
                break;
        }
    }

    //==================================================================================================
    private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {


            Log.i("callbackType", String.valueOf(callbackType));
            Log.i("result", result.toString());
            BluetoothDevice bluetoothDevice = result.getDevice();


                connectToDevice(bluetoothDevice);
                mDevicesAdapter.add(bluetoothDevice);
                mDevicesAdapter.notifyDataSetChanged();

        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            for (ScanResult sr : results) {
                Log.i("ScanResult - Results", sr.toString());
            }
        }

        @Override
        public void onScanFailed(int errorCode) {
            Log.e("Scan Failed", "Error Code: " + errorCode);
        }
    };
    //==================================================================================================
    public void connectToDevice(BluetoothDevice device) {
        if (mGatt == null) {
            mGatt = device.connectGatt(this, false,  mGattCallback);
            finishScanning();// will stop after first device detection
        }
    }
    //==================================================================================================
    private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, final int newState) {
            super.onConnectionStateChange(gatt, status, newState);

            if (newState == BluetoothProfile.STATE_CONNECTED) {
                Log.i(TAG, "Connected to GATT server.");
                if (mGatt.discoverServices()) {
                    Log.i(TAG, "Started service discovery.");
                } else {
                    Log.w(TAG, "Service discovery failed.");
                }
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                Log.i(TAG, "Disconnected from GATT server.");
            }
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    updateConnectButton(newState);
                }
            });
        }
//==================================================================================================
//        Callback called when a service is discovered
//        Make a list of supported GATT services and subscribe to the characteristics.
//==================================================================================================
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);

            List<BluetoothGattService> gattServices = getSupportedGattServices();

            if (gattServices == null) {
                Log.w(TAG, "No services found.");
                return;
            }

            mDevicesAdapter.updateScanningState(mScanning = false);
            finishScanning();

            for (BluetoothGattService gattService : gattServices) {
                List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
                for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {


                    if (gattCharacteristic.getUuid().equals(AssignedNumber.getBleUuid("Pressure"))) {

                        mGatt.setCharacteristicNotification(gattCharacteristic, true);// Enable notifications.
                        BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(AssignedNumber.getBleUuid("Client Characteristic Configuration"));
                        descriptor.setValue( BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE );
                        writeGattDescriptor(descriptor);
                        Log.i(TAG, "Pression characteristic subscription done");
                    }


                    if (gattCharacteristic.getUuid().equals(AssignedNumber.getBleUuid("switch led"))) {

                        mGatt.setCharacteristicNotification(gattCharacteristic, true);// Enable notifications.
                        Log.i(TAG, "SWITCH LED subscription done");
                    }

                    if (gattCharacteristic.getUuid().equals(AssignedNumber.getBleUuid("led state"))) {

                        mGatt.setCharacteristicNotification(gattCharacteristic, true);// Enable notifications.
                        BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(AssignedNumber.getBleUuid("Client Characteristic Configuration"));
                        descriptor.setValue( BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE );
                        writeGattDescriptor(descriptor);
                        Log.i(TAG, "LED STATE subscription done");
                    }

                    if (gattCharacteristic.getUuid().equals(AssignedNumber.getBleUuid("Temperature"))) {

                        mGatt.setCharacteristicNotification(gattCharacteristic, true);// Enable notifications.
                        BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(AssignedNumber.getBleUuid("Client Characteristic Configuration"));
                        descriptor.setValue( BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE );
                        writeGattDescriptor(descriptor);
                        Log.i(TAG, "Temperature characteristic subscription done");
                    }
                }
            }
        }

//==================================================================================================
//                          Callback called when a characteristic change
//              Check which characteristic has changed and update the TextView accordingly
//==================================================================================================
        @Override
        public void onCharacteristicChanged (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);

            if (characteristic.getUuid().equals(AssignedNumber.getBleUuid("Pressure"))) {
               // Log.i(TAG, "Pressure has changed");

                float pressure100 = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32,0).floatValue();
                final float pressure = pressure100 / 100.0f;  // 2 decimals
                runOnUiThread(new Runnable() {
                    public void run() {
                        TextView pressureTxt = (TextView) BleIotActivity.this.findViewById(R.id.Pvalue);
                        pressureTxt.setText(String.format("%.2f hPa", pressure));
                    }
                });
                Log.d(TAG, String.format("Update pressure: %.2f hPa", pressure));
            }

            if (characteristic.getUuid().equals(AssignedNumber.getBleUuid("led state"))) {
               // Log.i(TAG, "led state has changed");

              final int state = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16,0);
                runOnUiThread(new Runnable() {
                    public void run() {
                        if(state == 0){
                           TextView textLedState = (TextView) BleIotActivity.this.findViewById(R.id.textLedState);
                           textLedState.setText(String.format("LED OFF"));
                        }
                        else{
                            TextView textLedState = (TextView) BleIotActivity.this.findViewById(R.id.textLedState);
                            textLedState.setText(String.format("LED ON"));

                        }
                     }
                });
            }


            if (characteristic.getUuid().equals(AssignedNumber.getBleUuid("Temperature"))) {

             //   Log.i(TAG, "Temperature has changed");

                float temperature100 = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16,0).floatValue();
                final float temperature = temperature100 / 10.0f; // 2 decimals
                runOnUiThread(new Runnable() {
                    public void run() {
                        TextView temperatureTxt = (TextView) BleIotActivity.this.findViewById(R.id.Tvalue);
                        temperatureTxt.setText(String.format("%.1f°C", temperature));
                    }
                });
                Log.d(TAG, String.format("Update temperature: %.1f°C", temperature));
            }
        }

        /******************* Callback called when descriptor is written ***************************/
        /**** Indicates the result of the operation and deals with the descriptor write queue. ****/

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            Log.d(TAG, "GATT onDescriptorWrite()");

            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.d(TAG, "GATT: Descriptor wrote successfully."); //Operation ended successfully.
            } else {
                Log.d(TAG, "GATT: Error writing descriptor (" + status + ").");
            }

            descriptorWriteQueue.remove();

            if (descriptorWriteQueue.size() > 0) {
                mGatt.writeDescriptor(descriptorWriteQueue.element());
            }
        }

    };

//==================================================================================================
    /************************** Method to write a descriptor. *************************************/
//==================================================================================================
    public void writeGattDescriptor(BluetoothGattDescriptor descriptor) {
        descriptorWriteQueue.add(descriptor);

        Log.d(TAG, "Subscribed to " + descriptorWriteQueue.size() + " notification/s");

        try {
            if (descriptorWriteQueue.size() == 1)
                mGatt.writeDescriptor(descriptor);
        } catch (Exception e) {
            e.getLocalizedMessage();
        }
    }
//==================================================================================================
    /**
     * Retrieves a list of supported GATT services on the connected device. This should be
     * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
     *
     * @return A {@code List} of supported services.
     */
    public List<BluetoothGattService> getSupportedGattServices() {
        if (mGatt == null)
            return null;

        return mGatt.getServices();
    }
}
//==================================================================================================
AssignedNumber.java
package fr.enib.bleiot_android;

import android.util.SparseArray;

import java.util.UUID;

/**
 * Created by tomcot01 on 21/08/2014.
 * ARM University Program Copyright © ARM Ltd 2014
 */
public class AssignedNumber {
    private static SparseArray<String> sAssignedNumbers = new SparseArray<String>();


   // private static final String FORMAT_BLE_UUID_DESCRIPTOR = "0000%04x-0000-1000-8000-00805f9b34fb";

    //private static final String FORMAT_BLE_UUID = "0000%04x-0001-11e1-ac36-0002a5d5c51b";

    //private static final String FORMAT_BLE_UUID = "0000%04x-0000-1000-8000-00805f9b34fb";
    private static final String FORMAT_BLE_UUID = "0000%04x-0000-1000-8000-00805f9b34fb";



    static {
        // Services.
        // Taken from https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
        sAssignedNumbers.put(0x1811, "Alert Notification Service");
        sAssignedNumbers.put(0x180F, "Battery Service");
        sAssignedNumbers.put(0x1810, "Blood Pressure");
        sAssignedNumbers.put(0x1805, "Current Time Service");
        sAssignedNumbers.put(0x1818, "Cycling Power");
        sAssignedNumbers.put(0x1816, "Cycling Speed and Cadence");
        sAssignedNumbers.put(0x180A, "Device Information");
        sAssignedNumbers.put(0x1800, "Generic Access");
        sAssignedNumbers.put(0x1801, "Generic Attribute");
        sAssignedNumbers.put(0x1808, "Glucose");
        sAssignedNumbers.put(0x1809, "Health Thermometer");
        sAssignedNumbers.put(0x180D, "Heart Rate");
        sAssignedNumbers.put(0x1812, "Human Interface Device");
        sAssignedNumbers.put(0x1802, "Immediate Alert");
        sAssignedNumbers.put(0x1803, "Link Loss");
        sAssignedNumbers.put(0x1819, "Location and Navigation");
        sAssignedNumbers.put(0x1807, "Next DST Change Service");
        sAssignedNumbers.put(0x180E, "Phone Alert Status Service");
        sAssignedNumbers.put(0x1806, "Reference Time Update Service");
        sAssignedNumbers.put(0x1814, "Running Speed and Cadence");
        sAssignedNumbers.put(0x1813, "Scan Parameters");
        sAssignedNumbers.put(0x1804, "Tx Power");
        sAssignedNumbers.put(0x181A, "Environmental Sensing");
        sAssignedNumbers.put(0x181B, "Environmental Sensing2");
        sAssignedNumbers.put(0x181C, "User Data");
        //+++++++++++++++++++USER DEFINED SERVICES++++++++++++++++++
        sAssignedNumbers.put(0xFF10, "led service");
        // Characteristics.
        // Taken from https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx
        sAssignedNumbers.put(0x2A7E, "Aerobic Heart Rate Lower Limit");
        sAssignedNumbers.put(0x2A84, "Aerobic Heart Rate Upper Limit");
        sAssignedNumbers.put(0x2A7F, "Aerobic Threshold");
        sAssignedNumbers.put(0x2A80, "Age");
        sAssignedNumbers.put(0x2A43, "Alert Category ID");
        sAssignedNumbers.put(0x2A42, "Alert Category ID Bit Mask");
        sAssignedNumbers.put(0x2A06, "Alert Level");
        sAssignedNumbers.put(0x2A44, "Alert Notification Control Point");
        sAssignedNumbers.put(0x2A3F, "Alert Status");
        sAssignedNumbers.put(0x2A81, "Anaerobic Heart Rate Lower Limit");
        sAssignedNumbers.put(0x2A82, "Anaerobic Heart Rate Upper Limit");
        sAssignedNumbers.put(0x2A83, "Anaerobic Threshold");
        sAssignedNumbers.put(0x2A01, "Appearance");
        sAssignedNumbers.put(0x2A19, "Battery Level");
        sAssignedNumbers.put(0x2A49, "Blood Pressure Feature");
        sAssignedNumbers.put(0x2A35, "Blood Pressure Measurement");
        sAssignedNumbers.put(0x2A38, "Body Sensor Location");
        sAssignedNumbers.put(0x2A22, "Boot Keyboard Input Report");
        sAssignedNumbers.put(0x2A32, "Boot Keyboard Output Report");
        sAssignedNumbers.put(0x2A33, "Boot Mouse Input Report");
        sAssignedNumbers.put(0x2A5C, "CSC Feature");
        sAssignedNumbers.put(0x2A5B, "CSC Measurement");
        sAssignedNumbers.put(0x2A2B, "Current Time");
        sAssignedNumbers.put(0x2A66, "Cycling Power Control Point");
        sAssignedNumbers.put(0x2A65, "Cycling Power Feature");
        sAssignedNumbers.put(0x2A63, "Cycling Power Measurement");
        sAssignedNumbers.put(0x2A64, "Cycling Power Vector");
        sAssignedNumbers.put(0x2A99, "Database Change Increment");
        sAssignedNumbers.put(0x2A85, "Date of Birth");
        sAssignedNumbers.put(0x2A86, "Date of Threshold Assessment ");
        sAssignedNumbers.put(0x2A08, "Date Time");
        sAssignedNumbers.put(0x2A0A, "Day Date Time");
        sAssignedNumbers.put(0x2A09, "Day of Week");
        sAssignedNumbers.put(0x2A00, "Device Name");
        sAssignedNumbers.put(0x2A0D, "DST Offset");
        sAssignedNumbers.put(0x2A87, "Email Address");
        sAssignedNumbers.put(0x2A0C, "Exact Time 256");
        sAssignedNumbers.put(0x2A88, "Fat Burn Heart Rate Lower Limit");
        sAssignedNumbers.put(0x2A89, "Fat Burn Heart Rate Upper Limit");
        sAssignedNumbers.put(0x2A26, "Firmware Revision String");
        sAssignedNumbers.put(0x2A8A, "First Name");
        sAssignedNumbers.put(0x2A8B, "Five Zone Heart Rate Limits");
        sAssignedNumbers.put(0x2A8C, "Gender");
        sAssignedNumbers.put(0x2A51, "Glucose Feature");
        sAssignedNumbers.put(0x2A18, "Glucose Measurement");
        sAssignedNumbers.put(0x2A34, "Glucose Measurement Context");
        sAssignedNumbers.put(0x2A27, "Hardware Revision String");
        sAssignedNumbers.put(0x2A39, "Heart Rate Control Point");
        sAssignedNumbers.put(0x2A8D, "Heart Rate Max");
        sAssignedNumbers.put(0x2A37, "Heart Rate Measurement");
        sAssignedNumbers.put(0x2A8E, "Height");
        sAssignedNumbers.put(0x2A4C, "HID Control Point");
        sAssignedNumbers.put(0x2A4A, "HID Information");
        sAssignedNumbers.put(0x2A8F, "Hip Circumference");
        sAssignedNumbers.put(0x2A6F, "Humidity");
        sAssignedNumbers.put(0x2A2A, "IEEE 11073-20601 Regulatory Certification Data List");
        sAssignedNumbers.put(0x2A36, "Intermediate Cuff Pressure");
        sAssignedNumbers.put(0x2A1E, "Intermediate Temperature");
        sAssignedNumbers.put(0x2AA2, "Language");
        sAssignedNumbers.put(0x2A90, "Last Name");
        sAssignedNumbers.put(0x2A6B, "LN Control Point");
        sAssignedNumbers.put(0x2A6A, "LN Feature");
        sAssignedNumbers.put(0x2A0F, "Local Time Information");
        sAssignedNumbers.put(0x2A67, "Location and Speed");
        sAssignedNumbers.put(0x2A29, "Manufacturer Name String");
        sAssignedNumbers.put(0x2A91, "Maximum Recommended Heart Rate");
        sAssignedNumbers.put(0x2A21, "Measurement Interval");
        sAssignedNumbers.put(0x2A24, "Model Number String");
        sAssignedNumbers.put(0x2A68, "Navigation");
        sAssignedNumbers.put(0x2A46, "New Alert");
        sAssignedNumbers.put(0x2A04, "Peripheral Preferred Connection Parameters");
        sAssignedNumbers.put(0x2A02, "Peripheral Privacy Flag");
        sAssignedNumbers.put(0x2A50, "PnP ID");
        sAssignedNumbers.put(0x2A69, "Position Quality");
        sAssignedNumbers.put(0x2A6D, "Pressure");
        sAssignedNumbers.put(0x2A4E, "Protocol Mode");
        sAssignedNumbers.put(0x2A03, "Reconnection Address");
        sAssignedNumbers.put(0x2A52, "Record Access Control Point");
        sAssignedNumbers.put(0x2A14, "Reference Time Information");
        sAssignedNumbers.put(0x2A4D, "Report");
        sAssignedNumbers.put(0x2A4B, "Report Map");
        sAssignedNumbers.put(0x2A92, "Resting Heart Rate");
        sAssignedNumbers.put(0x2A40, "Ringer Control Point");
        sAssignedNumbers.put(0x2A41, "Ringer Setting");
        sAssignedNumbers.put(0x2A54, "RSC Feature");
        sAssignedNumbers.put(0x2A53, "RSC Measurement");
        sAssignedNumbers.put(0x2A55, "SC Control Point");
        sAssignedNumbers.put(0x2A4F, "Scan Interval Window");
        sAssignedNumbers.put(0x2A31, "Scan Refresh");
        sAssignedNumbers.put(0x2A5D, "Sensor Location");
        sAssignedNumbers.put(0x2A25, "Serial Number String");
        sAssignedNumbers.put(0x2A05, "Service Changed");
        sAssignedNumbers.put(0x2A28, "Software Revision String");
        sAssignedNumbers.put(0x2A93, "Sport Type for Aerobic and Anaerobic Thresholds");
        sAssignedNumbers.put(0x2A47, "Supported New Alert Category");
        sAssignedNumbers.put(0x2A48, "Supported Unread Alert Category");
        sAssignedNumbers.put(0x2A23, "System ID");
        sAssignedNumbers.put(0x2A6E, "Temperature");
        sAssignedNumbers.put(0x2A1C, "Temperature Measurement");
        sAssignedNumbers.put(0x2A1D, "Temperature Type");
        sAssignedNumbers.put(0x2A94, "Three Zone Heart Rate Limits");
        sAssignedNumbers.put(0x2A12, "Time Accuracy");
        sAssignedNumbers.put(0x2A13, "Time Source");
        sAssignedNumbers.put(0x2A71, "True Wind Direction");
        //+++++++++++++++++++USER DEFINED CHAR++++++++++++++++++
        sAssignedNumbers.put(0xFF12, "switch led");
        sAssignedNumbers.put(0xFF11, "led state");

        // GATT
        // https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-attribute-profile
        sAssignedNumbers.put(0x1800, "Generic Access Profile");
        sAssignedNumbers.put(0x1801, "Generic Attribute Profile");
        sAssignedNumbers.put(0x2800, "Primary Service");
        sAssignedNumbers.put(0x2801, "Secondary Service");
        sAssignedNumbers.put(0x2802, "Include");
        sAssignedNumbers.put(0x2803, "Characteristic");
        sAssignedNumbers.put(0x2900, "Characteristic Extended Properties");
        sAssignedNumbers.put(0x2901, "Characteristic User Description");
        sAssignedNumbers.put(0x2902, "Client Characteristic Configuration");
        sAssignedNumbers.put(0x2903, "Server Characteristic Configuration");
        sAssignedNumbers.put(0x2904, "Characteristic Format");
        sAssignedNumbers.put(0x2905, "Characteristic Aggregate Format");
        sAssignedNumbers.put(0x2A00, "Device Name");
        sAssignedNumbers.put(0x2A01, "Appearance");
        sAssignedNumbers.put(0x2A02, "Peripheral Privacy Flag");
        sAssignedNumbers.put(0x2A03, "Reconnection Address");
        sAssignedNumbers.put(0x2A04, "Peripheral Preferred Connection Parameters");
        sAssignedNumbers.put(0x2A05, "Service Changed");
    }

    public static UUID getBleUuid(String name) {
        for(int i = 0; i < sAssignedNumbers.size(); i++){
            int key = sAssignedNumbers.keyAt(i);
            if (sAssignedNumbers.valueAt(i).equals(name)) {
                return UUID.fromString(String.format(FORMAT_BLE_UUID, key));
            }
        }
        return null;
    }




    public static int get(String name) {
        for(int i = 0; i < sAssignedNumbers.size(); i++){
            int key = sAssignedNumbers.keyAt(i);
            if (sAssignedNumbers.valueAt(i).equals(name)) {
                return key;
            }
        }
        return -1;
    }
}