Android App点击按钮向ESP32写入BLE特征值失败问题
Android BLE向ESP32写入数据失败问题排查
问题背景
开发的Android应用可正常接收ESP32返回的BLE数据(示例格式:UPS%12345678%223%012.8%000%223%00.0%04%1%001%13.5%00.0%00.3%00.0%00.4%000.0%000.0%END),但点击按钮向ESP32写入构造字符串(如builderList.get(1).toString() + "%" + " ON" + "%" + "END")时,数据始终无法传输成功。
相关核心代码:
public class MainScreen extends AppCompatActivity implements Serializable, Observer { BluetoothAdapter mBluetoothAdapter; public static final String Tag="DetailBle"; boolean MAINSSTATUS; boolean SOLARSTATUS; private static boolean UPSSTATUS; boolean BATTERYFULL; String CHARGING_STATUS,CHARGING_LABEL; View view; LinearLayout statusLayout; int psckecked; Alarms alarms; List<BluetoothGattCharacteristic> characteristicsList = new ArrayList<>(); List<BluetoothGattService> servicesList; BleDevice bleDevice; BluetoothGattService service; List<StringBuilder> builderList; // UI组件定义 LinearLayout solarArrowLoad, solarArrowBattery, gridArrowLoad, gridArrowBattery,batteryArrowLoad; TextView solarToloadP,solarToBatteryCur; TextView solarCurrent,batteryVolt,batteryCurrent,SRnumber, gridVolt,loadPersent; TextView connetionStatus; Button upsStatus,upsMode,highCharging,powerSaving; ImageView solarPanel,battery,homeLoad,supply; int writeFlag; ClickDialog clickDialog; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail_ble); ObserverManager.Companion.getInstance().addObserver(this); mBluetoothAdapter=BluetoothAdapter.getDefaultAdapter(); BleDevice bleDevice1 = getIntent().getParcelableExtra("bleDevice"); if (bleDevice1 != null){ Log.d("","javed"+bleDevice1.getName()); start(bleDevice1); } else { Toast.makeText(this, "yaha dikaat hai ky bhai", Toast.LENGTH_SHORT).show(); } } void start(BleDevice bleDevice1){ bleDevice=bleDevice1; Log.d("","oldhai"+bleDevice.getName()); if (bleDevice!=null){ if (BleManager.getInstance().isConnected(bleDevice)){ initView(); setData(); try { Thread.sleep(1000); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } write("hello sir"); Log.d("Tag","msg"+write("i am coder")); Log.d("Tag","msg"+write("i am coder")); try { Thread.sleep(500); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } indicate(); try { Thread.sleep(1000); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } setMTU(); } else { Toast.makeText(this, "Device is not connected", Toast.LENGTH_SHORT).show(); Log.d(Tag+"onCreate","Device id not connected"); } } setConnectivityStatus(); } @Override protected void onStart() { super.onStart(); } @Override protected void onResume() { super.onResume(); } private void setConnectivityStatus() { if (getConnectivityStatus()) { connetionStatus.setText(getText(R.string.connected)); Log.d(Tag,"Connected"); } else { connetionStatus.setText(R.string.active_disconnected); Log.d(Tag,"Disconnected"); } } private boolean getConnectivityStatus() { return BleManager.getInstance().isConnected(bleDevice); } @Override protected void onDestroy() { super.onDestroy(); if (bleDevice!=null){ BleManager.getInstance().disconnect(bleDevice); BleManager.getInstance().destroy(); } stopNotification(); } private void initView() { servicesList = new ArrayList<>(); builderList= new ArrayList<>(); connetionStatus=findViewById(R.id.connected_status); solarToloadP=findViewById(R.id.solar_to_load_power); solarToBatteryCur=findViewById(R.id.solar_to_battery_current); SRnumber = findViewById(R.id.serialNO); gridVolt =findViewById(R.id.ip_volt); loadPersent=findViewById(R.id.load_presentge); batteryVolt=findViewById(R.id.battery_volt); batteryCurrent=findViewById(R.id.battrery_to_load_power); upsStatus=findViewById(R.id.ups_status); upsMode=findViewById(R.id.ups_mode); highCharging=findViewById(R.id.high_charging); powerSaving=findViewById(R.id.power_saving); solarPanel=findViewById(R.id.solar_panel); supply=findViewById(R.id.supply); battery=findViewById(R.id.battery); homeLoad=findViewById(R.id.load); gridArrowLoad =findViewById(R.id.grid_arroweup); gridArrowBattery =findViewById(R.id.grid_arrowdown); solarArrowLoad =findViewById(R.id.solar_arrow_up); solarArrowBattery =findViewById(R.id.solar_arrow_mid); batteryArrowLoad =findViewById(R.id.battery_to_load); } private void setData() { BluetoothGatt gatt = BleManager.getInstance().getBluetoothGatt(bleDevice); alarms=new Alarms(MainScreen.this); clickDialog = new ClickDialog(MainScreen.this); view =getWindow().getDecorView().findViewById(android.R.id.content); for (BluetoothGattService service : gatt.getServices()) { servicesList.add(service); } service = servicesList.get(2); characteristicsList.addAll(service.getCharacteristics()); upsStatus.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (!builderList.isEmpty()) { if (upsStatus.getText() == getString(R.string.ups_on)) { String input = builderList.get(1).toString() + "%" + "OFF" + "%" + "END"; Log.d("","upsss"+builderList.subList(1,10)); int status = write(input); if (status == 1) upsStatus.setText(getString(R.string.ups_off)); else Toast.makeText(MainScreen.this, "Operation Fail try again", Toast.LENGTH_SHORT).show(); } else { String input = builderList.get(1).toString() + "%" + " ON" + "%" + "END"; int status = write(input); if (status == 1) upsStatus.setText(getString(R.string.ups_on)); else Toast.makeText(MainScreen.this, "Operation Fail try again", Toast.LENGTH_SHORT).show(); } } } }); } // 缺失的write、indicate、setMTU、stopNotification方法实现 private int write(String input) { // 待实现 return 0; } private void indicate() { /* 待实现 */ } private void setMTU() { /* 待实现 */ } private void stopNotification() { /* 待实现 */ } }
排查与修复步骤
1. 修正字符串对比逻辑
代码中使用==对比按钮文本与字符串资源,会因对象引用不同导致判断错误,替换为内容对比:
// 原错误代码 if (upsStatus.getText() == getString(R.string.ups_on)) { ... } // 修正后 if (getString(R.string.ups_on).equals(upsStatus.getText().toString())) { ... }
2. 确认写入特征值的属性
确保选中的BLE特征值支持写入操作,遍历服务下的特征值并筛选可写入项:
// 在setData方法中添加特征值属性检查 for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) { int properties = characteristic.getProperties(); if ((properties & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0 || (properties & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0) { Log.d(Tag, "可写入特征UUID: " + characteristic.getUuid()); // 记录该特征值,后续写入使用 } }
必须使用ESP32端配置为接收写入的特征UUID,不能直接依赖servicesList.get(2)的索引。
3. 完善write方法实现
实现标准的BLE写入逻辑,确保数据编码与ESP32端一致:
private int write(String input) { if (bleDevice == null || !BleManager.getInstance().isConnected(bleDevice)) { Log.d(Tag, "设备未连接"); return -1; } BluetoothGatt gatt = BleManager.getInstance().getBluetoothGatt(bleDevice); if (gatt == null) { Log.d(Tag, "GATT实例为空"); return -1; } // 找到可写入的特征值(建议通过UUID匹配,而非索引) BluetoothGattCharacteristic writeChar = null; for (BluetoothGattCharacteristic chara : characteristicsList) { int prop = chara.getProperties(); if ((prop & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0) { writeChar = chara; break; } } if (writeChar == null) { Log.d(Tag, "未找到可写入特征值"); return -1; } // 设置数据(UTF-8编码,需与ESP32端一致) writeChar.setValue(input.getBytes(StandardCharsets.UTF_8)); // 执行写入,WRITE_TYPE_DEFAULT需要设备应答 boolean success = gatt.writeCharacteristic(writeChar); return success ? 1 : 0; }
4. 监听写入结果回调
在BleManager的BluetoothGattCallback中实现写入回调,确认操作是否成功:
@Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); if (status == BluetoothGatt.GATT_SUCCESS) { Log.d(Tag, "数据写入成功"); // 可在此更新UI状态,无需依赖write方法的返回值 } else { Log.d(Tag, "写入失败,状态码: " + status); // 状态码含义:GATT_FAILURE(133)为通用失败,GATT_INVALID_ATTRIBUTE_LENGTH(135)为数据过长需调整MTU } }
5. 匹配ESP32端数据格式
检查写入字符串是否符合ESP32的解析逻辑:
- 移除多余空格:比如
" ON"改为"ON",确保与ESP32端指令格式一致 - 确认
builderList.get(1)的内容是否为ESP32预期的指令前缀 - 结尾的
%END需和ESP32端的结束标记完全匹配
6. 优化BLE操作线程
移除代码中的Thread.sleep(),BLE操作依赖回调而非阻塞等待,避免主线程卡顿。
7. 确认MTU设置有效性
若写入字符串长度超过23字节(默认MTU),需确保MTU协商成功:
private void setMTU() { BluetoothGatt gatt = BleManager.getInstance().getBluetoothGatt(bleDevice); if (gatt != null) { // 请求更大的MTU,最大支持512 gatt.requestMtu(512); } } // 在BluetoothGattCallback中监听MTU变化 @Override public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { super.onMtuChanged(gatt, mtu, status); if (status == BluetoothGatt.GATT_SUCCESS) { Log.d(Tag, "MTU协商成功: " + mtu); } else { Log.d(Tag, "MTU协商失败"); } }
内容的提问来源于stack exchange,提问作者Javed Quantum
相关产品推荐
相关产品推荐

