ESP32S蓝牙08

ESP32S蓝牙08

继续ESP32S的BLE蓝牙学习。在上一篇中,我们完成了APP对BLE蓝牙作为客户端,是如何连接服务器端,并且与服务器端的蓝牙设备进行通讯。今天我们继续完成手机APP作为服务器端时,要怎样广播服务消息,如何与连接的客户端进行通讯的。

需要知道的是,安卓是从4.3(API 18版本)才开始支持蓝牙BLE客户端,而从5.0(API 21版本)以后才开始支持BLE服务器端的。看来我之前的升级Eclipse以及Android SDK(API 27版本)是非常及时的,也才有这一系列的蓝牙学习。

我们要做的就是BLEServer,和前一篇中的BLE客户端程序进行通讯,如上图所示,两部手机分别安装了客户端和服务器程序,然后就可以互相收发消息了。

还是先上源码吧,里面有注释。

这个是主程序  MainActivity. java

package com.example.bleserver;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.os.ParcelUuid;

import android.annotation.SuppressLint;

import android.bluetooth.BluetoothAdapter;

import android.bluetooth.BluetoothDevice;

import android.bluetooth.BluetoothGatt;

import android.bluetooth.BluetoothGattCharacteristic;

import android.bluetooth.BluetoothGattDescriptor;

import android.bluetooth.BluetoothGattServer;

import android.bluetooth.BluetoothGattServerCallback;

import android.bluetooth.BluetoothGattService;

import android.bluetooth.BluetoothManager;

import android.bluetooth.BluetoothProfile;

import android.bluetooth.le.AdvertiseCallback;

import android.bluetooth.le.AdvertiseData;

import android.bluetooth.le.AdvertiseSettings;

import android.bluetooth.le.BluetoothLeAdvertiser;

import android.content.Context;

import android.content.Intent;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

import java.util.UUID;

@SuppressLint("NewApi")

public class MainActivity extends AppCompatActivity {

    //public final static UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");  //通用蓝牙的标志

    private UUID mServiceUUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");

    private UUID mReadUUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");

    private UUID mWriteUUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");

   

    private Button scan_button, send_button, discon_button;

    private TextView msgstr;

    private EditText msgstr02;

    private BluetoothAdapter bleadapter;

    private BluetoothLeAdvertiser mBluetoothLeAdvertiser;

    private BluetoothGatt bluetoothGatt;

    private BluetoothGattServer gattServer;

    private BluetoothGattService bluetoothGattServices;

    private BluetoothDevice bluetoothDevice;

    private BluetoothGattCharacteristic character_read, character_write;

    private int inval=0;

    private boolean connected = false;

    private Handler handler = new Handler() {

    @Override

    public void handleMessage(Message msg) {

        super.handleMessage(msg);

                msgstr02.setText(msgstr02.getText().toString() + "in: " + (String) msg.obj);

    }

    };

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

     

        msgstr = (TextView) findViewById(R.id.txt_msg);

        msgstr02 = (EditText) findViewById(R.id.txt_msg02);

        scan_button = (Button) findViewById(R.id.btn_scan);

        send_button = (Button) findViewById(R.id.btn_send);

        discon_button = (Button) findViewById(R.id.btn_discon);

        msgstr02.setFocusable(false);

       

        //初始化ble设配器

        BluetoothManager manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

        bleadapter = manager.getAdapter();

        //判断蓝牙是否开启,若是关闭则请求打开蓝牙

        if (bleadapter == null || !bleadapter.isEnabled()) {

            //方式一:请求打开蓝牙

            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

            startActivityForResult(intent, 1);

        }

        // 获取蓝牙ble广播对象

        assert bleadapter != null;

        mBluetoothLeAdvertiser = bleadapter.getBluetoothLeAdvertiser();

        gattServer = manager.openGattServer(this, bluetoothGattServerCallback);

       

        //BLE服务的初始化配置,很重要

        //配置的顺序是 服务service  特征(通道)Characteristic  属性Descriptor

        //配置服务名、 主服务类型

        BluetoothGattService service=new BluetoothGattService(mServiceUUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);

        //配置一个读的特征 (可读、可写、可侦听)

        character_read=new BluetoothGattCharacteristic(mReadUUID,

             BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_NOTIFY,

             BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);

        BluetoothGattDescriptor descriptor=new BluetoothGattDescriptor(mReadUUID,

             BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);

        character_read.addDescriptor(descriptor);

        service.addCharacteristic(character_read);

        //配置一个写的特征  (可写)

        character_write=new BluetoothGattCharacteristic(mWriteUUID, BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE);

        service.addCharacteristic(character_write);

        //添加到

        gattServer.addService(service);

       

       

        //开启广播按钮

        scan_button.setOnClickListener(new View.OnClickListener() {

        @Override

            public void onClick(View v) {

             //开启广播需要传入三个参数: 基本设置   附加数据   回调函数

             AdvertiseSettings settings = new AdvertiseSettings.Builder()

                        .setConnectable(true) //是否被连接

                        .setTimeout(0)        //超时时间

                        .build();

        

                //广播数据设置

                AdvertiseData advertiseData = new AdvertiseData.Builder()

                        .setIncludeDeviceName(true)    //是否在广播中携带设备的名称

                        .setIncludeTxPowerLevel(true//是否在广播中携带信号强度

                        .build();

                //扫描回应的广播设置

                AdvertiseData scanResponseData = new AdvertiseData.Builder()

                        .setIncludeTxPowerLevel(true//是否在广播中携带设备的名称

                        .addServiceData(new ParcelUuid(mServiceUUID), new byte[]{1,2}) //scanrecord中添加的数据

                        .build();

        

                //设置BLE设备的名称

                bleadapter.setName("BLEServer");

                //开启广播

                mBluetoothLeAdvertiser.startAdvertising(settings, advertiseData, scanResponseData, mAdvertiseCallback);           

        }

        });

       

        //发送消息按钮

        send_button.setOnClickListener(new View.OnClickListener() {

        @Override

            public void onClick(View v) {

             if(connected == true) {

                 inval += 1;

                 String str = "hello" + inval + "\n\r";

                 character_write.setValue(str);

                    gattServer.notifyCharacteristicChanged(bluetoothDevice, character_write, false);

                    msgstr02.setText(msgstr02.getText().toString() + "ou: " + str);

             }

                         

        }

        });

       

        //停止广播按钮

        discon_button.setOnClickListener(new View.OnClickListener() {

        @Override

            public void onClick(View v) {

             if (connected == true) {

                mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);

                connected = false;

             }

        }

        });

     

    }

   

    private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {

        @Override

        public void onStartSuccess(AdvertiseSettings settingsInEffect) {

            super.onStartSuccess(settingsInEffect);

            msgstr.setText("开启广播成功" + "\n");

        }

        @Override

        public void onStartFailure(int errorCode) {

            super.onStartFailure(errorCode);

            msgstr.setText("开启广播失败" + "\n");

        }

    };

   

    //广播服务管理状态回调

    private BluetoothGattServerCallback bluetoothGattServerCallback=new BluetoothGattServerCallback() {

       

    //连接状态的回调

        @Override

        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {

            super.onConnectionStateChange(device, status, newState);

            if(newState == BluetoothProfile.STATE_CONNECTED) {

                bluetoothDevice = device;

                msgstr.setText("已连接到  " + device.getName() + "\n");

                connected = true;

            }

            if(newState == BluetoothProfile.STATE_DISCONNECTED) {

            msgstr.setText("连接已断开 " + "\n");

            msgstr02.setText("");

            }

        }

       

        @Override

        public void onServiceAdded(int status,BluetoothGattService service){

            super.onServiceAdded(status,service);

            msgstr.setText("添加服务成功");

        }

        //获取接收,接收的数据为参数中的value

        @Override

        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {

            super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);

                gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);

                Message mesg = new Message();

                mesg.what = 1;

                mesg.obj = new String(value);

                MainActivity.this.handler.sendMessage(mesg);

        }

        @Override

        public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {

            super.onDescriptorReadRequest(device, requestId, offset, descriptor);

        }

       

        @Override

        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {

            super.onCharacteristicReadRequest(device, requestId, offset, characteristic);

           

        }

        @Override

        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {

            super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);

        }

    };

   

}

   

   

   

这个是界面设计   activity_main. xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

   xmlns:tools="http://schemas.android.com/tools"

   android:layout_width="match_parent"

   android:layout_height="match_parent"

   android:orientation="vertical"

   android:paddingBottom="@dimen/activity_vertical_margin"

   android:paddingLeft="@dimen/activity_horizontal_margin"

   android:paddingRight="@dimen/activity_horizontal_margin"

   android:paddingTop="@dimen/activity_vertical_margin"

   tools:context=".MainActivity" >

  

   <Button

      android:id="@+id/btn_scan"

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="开始广播" />

  

   <Button

      android:id="@+id/btn_send"

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="发送消息" />

   <Button

      android:id="@+id/btn_discon"

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="停止广播" />

  

   <TextView

      android:id="@+id/txt_msg"

      android:layout_width="match_parent"

      android:layout_height="wrap_content" />

  

   <EditText

      android:id="@+id/txt_msg02"

      android:minLines="12"

      android:gravity="top"

      android:layout_width="match_parent"

      android:layout_height="match_parent" />

</LinearLayout>

这个是安卓的版本号以及权限申请    在AndroidManifest. xml

<uses-sdk

        android:minSdkVersion="11"

        android:targetSdkVersion="21" />

   

     <!-- 添加蓝牙权限 -->

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

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

    <uses-feature android:name="android.hardware.location.gps" />

    <!-- Android6.0 蓝牙扫描才须要-->

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>

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

整体回顾一下:BLE蓝牙服务器的配置是关键的,配置的顺序是: 服务service——特征(通道)Characteristic——属性Descriptor。

在这里,我还是沿用蓝牙小车ESP32S的广播,在最这里使用指定的UUID方式,为这个服务器设置了一个读通道和一个写通道。(UUID要和前一篇的客户端APP中的匹配,但是特别要注意的是,服务器端的读和写与客户端是相反的。也就是服务器端的读(输入)就是客户端的写(输出), 相反服务器端的写(输出)就是客户端的读(输入))

mServiceUUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");

mReadUUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");

mWriteUUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");

    在服务器端,我们要把读的通道设置为(可读、可写、可侦听),这样才能收到从客户端发过来的消息。写的通道比较简单,只要设置成(可写)就可以了。

ESP32S3是一款由Espressif Systems公司生产的基于Arm Cortex-M4的单片机,它集成了蓝牙功能,使得开发人员能够在物联网应用中实现设备间的无线通信。ESP32S3支持低功耗蓝牙(BLE)和经典蓝牙(BR/EDR),这对于数据传输非常有用。 要使用ESP32S3进行蓝牙数据传输,通常会遵循以下步骤: 1. **初始化蓝牙模块**:首先,需要通过API(如ESP_BLE_API或ESP_GAP_CONFIG_API)初始化蓝牙功能,并配对或建立连接到其他蓝牙设备。 2. **创建服务和特性(GATT)**:ESP32S3支持GATT(Generic Attribute Profile),通过定义服务(如Characteristics)来组织数据。你可以创建数据发送和接收的服务以及相应的特性,比如Characteristic Value UUID。 3. **数据发送**:当你想要发送数据时,可以将数据写入某个Characteristic,使用`esp_ble_gatt_write()`等函数。确保你选择的特性支持写操作(Write Without Response或Write With Response)。 4. **数据接收**:对于接收数据,监听Characteristic的值改变事件(如`ESP_GATTS_EVT_WRITE`)。当接收到数据时,可以从Characteristic的值中读取。 5. **错误处理和回调**:确保为可能出现的错误和事件处理设置恰当的回调函数,以便于处理异常情况。 6. **断开连接后重连**:如果需要在设备间维持长连接,可能需要实现连接断开后的自动重连机制。 相关问题: 1. 如何在ESP32S3上设置BLE服务和特性? 2. 蓝牙传输过程中如何保证数据的安全性和可靠性? 3. 如果连接不稳定,应该如何优化ESP32S3的蓝牙通信?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tongyue

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值