BLE 장치에 연결

Sep 07 2020

그래서 이름이있는 모든 BLE 장치를 찾는이 앱을 만들었습니다. 그러나 특정 필드 중 하나를 클릭 가능하고 자동으로 장치에 연결하여 쓰기 / 읽기를 시작할 수 있도록하려면 어떻게해야합니까?

어댑터

public class ListAdapter_BTLE_Devices extends ArrayAdapter<BTLE_Device> {

    Activity activity;
    int layoutResourceID;
    ArrayList<BTLE_Device> devices;

    public ListAdapter_BTLE_Devices(Activity activity, int resource, ArrayList<BTLE_Device> objects) {
        super(activity.getApplicationContext(), resource, objects);
        this.activity = activity;
        layoutResourceID = resource;
        devices = objects;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if (convertView == null) {
            LayoutInflater inflater =
                    (LayoutInflater) activity.getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(layoutResourceID, parent, false);
        }

        BTLE_Device device = devices.get(position);
        String name = device.getName();
        String address = device.getAddress();
        int rssi = device.getRSSI();

        TextView BLE_name = (TextView) convertView.findViewById(R.id.BLE_name);
        if (name != null && name.length() > 0) {
            BLE_name.setText(device.getName());
        }
        else {
            BLE_name.setText("No Name");
        }

        TextView BLE_rssi = (TextView) convertView.findViewById(R.id.BLE_rssi);
        BLE_rssi.setText("RSSI: " + Integer.toString(rssi));

        TextView BLE_macaddr = (TextView) convertView.findViewById(R.id.BLE_macaddr);
        if (address != null && address.length() > 0) {
            BLE_macaddr.setText("MAC-addr: "+device.getAddress());
        }
        else {
            BLE_macaddr.setText("No Address");
        }

        return convertView;
    }
}

편집하다

지금은 GATT에 연결되어있을 것 같아서 제가 한 일은 .. 먼저 Mainactivity 에서 MAC-addr을 가져 와서 인 텐트에 저장하고 클릭시 다른 활동을 시작했습니다. 여기서 나는 다음을했다DeviceAddress = intent.getStringExtra(MainActivity.EXTRAS_BLE_ADDRESS);

BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(DeviceAddress);

device.connectGatt(this, false, mGattCallback);

connectGatt를 호출하면 메시지 Log.d(TAG, "Connection State: 1");가 인쇄됩니다. 이것이 올바른 방법입니까?


private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            Log.d(TAG, "Connection State Change: "+status+" -> "+connectionState(newState));
            if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
                /*
                 * Once successfully connected, we must next discover all the services on the
                 * device before we can read and write their characteristics.
                 */
                Log.d(TAG, "Connection State: 1");
                gatt.discoverServices();
            } else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) {
                /*
                 * If at any point we disconnect, send a message to clear the weather values
                 * out of the UI
                 */
                Log.d(TAG, "Connection State: 2");
            } else if (status != BluetoothGatt.GATT_SUCCESS) {
                /*
                 * If there is a failure at any stage, simply disconnect
                 */
                Log.d(TAG, "Connection State: 3");
                gatt.disconnect();
            }
        }

답변

ThomasMorris Sep 07 2020 at 21:24

장치에 연결하려면 먼저 콜백을 실행하는 BLE 스캔을 수행하고 (시작 코드를 사용하는 경우) 발견 된 장치 목록에 추가해야합니다.

찾고있는 장치 만 허용하려면 필터를 추가하십시오. BLE가 최대 31 바이트의 패킷을 광고하므로 여기에 제조업체 ID 또는 데이터 등과 같은 장치를 식별하는 데이터가 있어야합니다. 또는 간단한 프로젝트에서 작업하는 경우 장치 주소에 프로그래밍 방식으로 하드 코딩 할 수 있습니다.

그런 다음이 장치가 스캔에서 발견되면 BLE 스캔을 중지하고 자동으로 연결 요청을 대기열에 넣을 수 있습니다. 이렇게하면 GATT 요청이 만들어 지므로 GATT 서비스에 대한 액세스 권한이 부여되어 장치의 특성이 부여됩니다.

niedev Sep 15 2020 at 20:50

블루투스 LE에 문제가있는 경우 블루투스 파일 라이브러리를 사용하는 것이 좋습니다 (바퀴를 재발 명하지 마세요. 라이브러리를 만드는 데 약 3/4 개월이 걸렸습니다. 블루투스 파일 통신은 정말 까다로울 수 있습니다). 오픈 소스이므로 구현 예제가있는 코드도 볼 수 있습니다. github 페이지를 링크합니다. https://github.com/niedev/BluetoothCommunicator

프로젝트에서 라이브러리를 사용하려면 루트 build.gradle (프로젝트)에 jitpack.io를 추가해야합니다.

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

그런 다음 마지막 버전의 BluetoothCommunicator를 앱 build.gradle에 추가합니다.

dependencies {
        implementation 'com.github.niedev:BluetoothCommunicator:1.0.6'
}

이 라이브러리를 사용하려면 매니페스트에 다음 권한을 추가하세요.

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

그런 다음 android : largeHeap = "true"를 매니페스트의 애플리케이션 태그에 추가합니다.
예제

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<application
    android:name="com.bluetooth.communicatorexample.Global"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:largeHeap="true"
    android:theme="@style/Theme.Speech">
    <activity android:name="com.bluetooth.communicatorexample.MainActivity"
        android:configChanges="orientation|screenSize">

        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

libray를 다운로드하고 매니페스트를 설정하면 블루투스 커뮤니케이터 개체를 만들어야합니다. 블루투스 저에너지 라이브러리의 모든 작업을 처리하는 개체입니다. 여러 활동에서 블루투스 연결을 관리하려면 저장하는 것이 좋습니다. 이 개체는 Application을 확장하고 getter를 만드는 사용자 지정 클래스의 속성으로 다음을 사용하여 모든 활동 또는 서비스에서 bluetoothCommunicator에 액세스 할 수 있습니다.

((custom class name) getApplication()).getBluetoothCommunicator();

다음 단계는 bluetoothCommunicator를 초기화하는 것입니다. 매개 변수는 다음과 같습니다. 컨텍스트, 다른 장치가 우리를 볼 이름 (18 자로 제한되며 BluetoothTools.getSupportedUTFCharacters (context)에 나열된 문자 만 가능합니다. 광고 비콘의 바이트 수) 제한적 임) 및 전략 (현재 지원되는 유일한 상태는 BluetoothCommunicator.STRATEGY_P2P_WITH_RECONNECTION)

bluetoothCommunicator = new BluetoothCommunicator(this, "device name", BluetoothCommunicator.STRATEGY_P2P_WITH_RECONNECTION);

그런 다음 블루투스 커뮤니케이터 콜백을 추가하면 콜백이 블루투스 커뮤니케이터의 모든 이벤트를 수신합니다.

bluetoothCommunicator.addCallback(new BluetoothCommunicator.Callback() {
    @Override
    public void onBluetoothLeNotSupported() {
        super.onBluetoothLeNotSupported();
        
        Notify that bluetooth low energy is not compatible with this device
    }
   
    @Override
    public void onAdvertiseStarted() {
        super.onAdvertiseStarted();

        Notify that advertise has started, if you want to do something after the start of advertising do it here, because
        after startAdvertise there is no guarantee that advertise is really started (it is delayed)
    }

    @Override
    public void onDiscoveryStarted() {
        super.onDiscoveryStarted();

        Notify that discovery has started, if you want to do something after the start of discovery do it here, because
        after startDiscovery there is no guarantee that discovery is really started (it is delayed)
    }

    @Override
    public void onAdvertiseStopped() {
        super.onAdvertiseStopped();

        Notify that advertise has stopped, if you want to do something after the stop of advertising do it here, because
        after stopAdvertising there is no guarantee that advertise is really stopped (it is delayed)
    }

    @Override
    public void onDiscoveryStopped() {
        super.onDiscoveryStopped();

        Notify that discovery has stopped, if you want to do something after the stop of discovery do it here, because
        after stopDiscovery there is no guarantee that discovery is really stopped (it is delayed)
    }

    @Override
    public void onPeerFound(Peer peer) {
        super.onPeerFound(peer);
        
        Here for example you can save peer in a list or anywhere you want and when the user
        choose a peer you can call bluetoothCommunicator.connect(peer founded) but if you want to
        use a peer for connect you have to have peer updated (see onPeerUpdated or onPeerLost), if you use a
        non updated peer the connection might fail
        instead if you want to immediate connect where peer is found you can call bluetoothCommunicator.connect(peer) here
    }

    @Override
    public void onPeerLost(Peer peer){
        super.onPeerLost(peer);
        
        It means that a peer is out of range or has interrupted the advertise,
        here you can delete the peer lost from a eventual collection of founded peers
    }

    @Override
    public void onPeerUpdated(Peer peer,Peer newPeer){
        super.onPeerUpdated(peer,newPeer);

        It means that a founded peer (or connected peer) has changed (name or address or other things),
        if you have a collection of founded peers, you need to replace peer with newPeer if you want to connect successfully to that peer.

        In case the peer updated is connected and you have saved connected peers you have to update the peer if you want to successfully
        send a message or a disconnection request to that peer.
    }

    @Override
    public void onConnectionRequest(Peer peer){
        super.onConnectionRequest(peer);

        It means you have received a connection request from another device (peer) (that have called connect)
        for accept the connection request and start connection call bluetoothCommunicator.acceptConnection(peer);
        for refusing call bluetoothCommunicator.rejectConnection(peer); (the peer must be the peer argument of onConnectionRequest)
    }

    @Override
    public void onConnectionSuccess(Peer peer,int source){
        super.onConnectionSuccess(peer,source);

        This means that you have accepted the connection request using acceptConnection or the other
        device has accepted your connection request and the connection is complete, from now on you
        can send messages or data (or disconnection request) to this peer until onDisconnected

        To send messages to all connected peers you need to create a message with a context, a header, represented by a single character string
        (you can use a header to distinguish between different types of messages, or you can ignore it and use a random
        character), the text of the message, or a series of bytes if you want to send any kind of data and the peer you want to send the message to
        (must be connected to avoid errors), example: new Message(context,"a","hello world",peer);
        If you want to send message to a specific peer you have to set the sender of the message with the corresponding peer.

        To send disconnection request to connected peer you need to call bluetoothCommunicator.disconnect(peer);
    }

    @Override
    public void onConnectionFailed(Peer peer,int errorCode){
        super.onConnectionFailed(peer,errorCode);

        This means that your connection request is rejected or has other problems,
        to know the cause of the failure see errorCode (BluetoothCommunicator.CONNECTION_REJECTED
        means rejected connection and BluetoothCommunicator.ERROR means generic error)
    }

    @Override
    public void onConnectionLost(Peer peer){
        super.onConnectionLost(peer);

        This means that a connected peer has lost the connection with you and the library is trying
        to restore it, in this case you can update the gui to notify this problem.

        You can still send messages in this situation, all sent messages are put in a queue
        and sent as soon as the connection is restored
    }

    @Override
    public void onConnectionResumed(Peer peer){
        super.onConnectionResumed(peer);
        
        Means that connection lost is resumed successfully
    }

    @Override
    public void onMessageReceived(Message message,int source){
        super.onMessageReceived(message,source);

        Means that you have received a message containing TEXT, for know the sender you can call message.getSender() that return
        the peer that have sent the message, you can ignore source, it indicate only if you have received the message
        as client or as server
    }

    @Override
    public void onDataReceived(Message data,int source){
        super.onDataReceived(data,source);

        Means that you have received a message containing DATA, for know the sender you can call message.getSender() that return
        the peer that have sent the message, you can ignore source, it indicate only if you have received the message
        as client or as server
    }

    @Override
    public void onDisconnected(Peer peer,int peersLeft){
        super.onDisconnected(peer,peersLeft);

        Means that the peer is disconnected, peersLeft indicate the number of connected peers remained
    }

    @Override
    public void onDisconnectionFailed(){
        super.onDisconnectionFailed();

        Means that a disconnection is failed, super.onDisconnectionFailed will reactivate bluetooth for forcing disconnection
        (however the disconnection will be notified in onDisconnection)
    }
});

마지막으로 검색 및 / 또는 광고를 시작할 수 있습니다.

bluetoothCommunicator.startAdvertising();
bluetoothCommunicator.startDiscovery();

수행 할 수있는 다른 모든 작업은 이전에 작성한 콜백 코드의 주석으로 설명됩니다.