Anonymous
Обмен данными датчиков ESP32C6 с BLE 5.0 для каждого кода Arduino и кода Android Studio (JAVA)
Сообщение
Anonymous » 24 ноя 2024, 23:50
У меня есть проект, в котором я хочу прочитать данные датчика из ESP32C6 с помощью BLE 5.0
и я действительно запутался и не знаю, как кодировать настоящий BLE 5.0, но это мое задание. Не могли бы вы мне с этим помочь?
Проблема:
Я хочу прочитать данные датчика моего ESP32C6, но код Android Studio не подключается. с моим устройством и поэтому не обмениваюсь нужными мне данными и не отображаю их в моем приложении. Не могли бы вы мне с этим помочь?
Код Arduino
Код: Выделить всё
#include
#include
#include
#include
#include
#include
#include "MAX30105.h" // Korrigierte Bibliothek
#include "heartRate.h" // Zusätzliche Bibliothek für Herzfrequenzberechnung
// BLE UUIDs
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
// Pin Definitions
#define OPA344_PIN A0
// Task handles for core management
TaskHandle_t Task1;
TaskHandle_t Task2;
// Mutex for protecting shared resources
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
SemaphoreHandle_t xMutex = NULL;
// Sensor objects
Adafruit_MPU6050 mpu;
MAX30105 particleSensor;
// Variables für Herzfrequenzberechnung
const byte RATE_SIZE = 4; // Größe des Arrays für die Mittelwertbildung
byte rates[RATE_SIZE]; // Array zur Speicherung der letzten Herzfrequenzen
byte rateSpot = 0;
long lastBeat = 0; // Zeit seit dem letzten Herzschlag
float beatsPerMinute;
int beatAvg;
// BLE objects
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
// Shared data structure
struct SensorData {
// MPU6050 data
float accX, accY, accZ;
float gyroX, gyroY, gyroZ;
// MAX30102 data
uint32_t red, ir;
float heartRate;
int avgHeartRate;
// OPA344 data
float soundLevel;
} sensorData;
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
Serial.println("Device connected!");
}
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
Serial.println("Device disconnected!");
}
};
// Core 0: Sensor data acquisition
void SensorTask(void * parameter) {
for(;;) {
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// Read MPU6050
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
sensorData.accX = a.acceleration.x;
sensorData.accY = a.acceleration.y;
sensorData.accZ = a.acceleration.z;
sensorData.gyroX = g.gyro.x;
sensorData.gyroY = g.gyro.y;
sensorData.gyroZ = g.gyro.z;
// Read MAX30102 and calculate heart rate
sensorData.ir = particleSensor.getIR();
if (checkForBeat(sensorData.ir)) {
long delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0);
if (beatsPerMinute < 255 && beatsPerMinute > 20) {
rates[rateSpot++] = (byte)beatsPerMinute;
rateSpot %= RATE_SIZE;
// Durchschnitt berechnen
beatAvg = 0;
for (byte x = 0; x < RATE_SIZE; x++)
beatAvg += rates[x];
beatAvg /= RATE_SIZE;
sensorData.heartRate = beatsPerMinute;
sensorData.avgHeartRate = beatAvg;
}
}
// Read OPA344
int rawValue = analogRead(OPA344_PIN);
sensorData.soundLevel = (rawValue * 3.3) / 4095.0;
xSemaphoreGive(xMutex);
}
vTaskDelay(pdMS_TO_TICKS(10)); // 100Hz sampling rate
}
}
// Core 1: BLE and data processing
void ProcessingTask(void * parameter) {
for(;;) {
if (deviceConnected && xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// Format data for BLE transmission
String sensorDataStr =
"ACC:" + String(sensorData.accX) + "," +
String(sensorData.accY) + "," +
String(sensorData.accZ) +
";GYRO:" + String(sensorData.gyroX) + "," +
String(sensorData.gyroY) + "," +
String(sensorData.gyroZ) +
";HR:" + String(sensorData.heartRate) +
";AVG_HR:" + String(sensorData.avgHeartRate) +
";SND:" + String(sensorData.soundLevel);
// Send via BLE
pCharacteristic->setValue(sensorDataStr.c_str());
pCharacteristic->notify();
xSemaphoreGive(xMutex);
}
vTaskDelay(pdMS_TO_TICKS(100)); // 10Hz update rate for BLE
}
}
void setup() {
Serial.begin(115200);
Wire.begin();
// Create mutex
xMutex = xSemaphoreCreateMutex();
// Initialize MPU6050
if (!mpu.begin()) {
Serial.println("MPU6050 not found!");
while (1) delay(10);
}
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
// Initialize MAX30102
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
Serial.println("MAX30102 not found!");
while (1) delay(10);
}
// Konfiguration für den MAX30102
particleSensor.setup();
particleSensor.setPulseAmplitudeRed(0x0A);
particleSensor.setPulseAmplitudeGreen(0);
particleSensor.setPulseAmplitudeIR(0x0A);
particleSensor.setSampleRate(200); // Setzt die Sample Rate auf 200Hz
particleSensor.setFIFOAverage(4); // Setzt den Durchschnitt auf 4 Samples
// Initialize BLE
BLEDevice::init("ESP32C6");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06);
pAdvertising->setMaxPreferred(0x12);
BLEDevice::startAdvertising();
// Create tasks for each core
xTaskCreatePinnedToCore(
SensorTask, // Task function
"SensorTask", // Name
10000, // Stack size
NULL, // Parameters
1, // Priority
&Task1, // Task handle
0 // Core ID (0)
);
xTaskCreatePinnedToCore(
ProcessingTask,
"ProcessingTask",
10000,
NULL,
1,
&Task2,
1 // Core ID (1)
);
Serial.println("Setup complete!");
}
void loop() {
// Empty loop as tasks handle all the work
vTaskDelay(pdMS_TO_TICKS(1000));
}
Код Android Studio:
Код: Выделить всё
package com.example.project;
import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQUEST_CODE = 1;
private static final String DEVICE_NAME = "ESP32C6";
private static final UUID SERVICE_UUID = UUID.fromString("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
private static final UUID CHARACTERISTIC_UUID = UUID.fromString("beb5483e-36e1-4688-b7f5-ea07361b26a8");
private BluetoothManager bluetoothManager;
private BluetoothAdapter bluetoothAdapter;
private BluetoothLeScanner bluetoothLeScanner;
private BluetoothGatt bluetoothGatt;
private Button btnScan;
private TextView tvConnectionStatus, tvAccData, tvGyroData, tvHeartRate, tvSoundLevel;
private boolean scanning = false;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeViews();
setupBluetooth();
checkPermissions();
}
private void initializeViews() {
btnScan = findViewById(R.id.btnScan);
tvConnectionStatus = findViewById(R.id.tvConnectionStatus);
tvAccData = findViewById(R.id.tvAccData);
tvGyroData = findViewById(R.id.tvGyroData);
tvHeartRate = findViewById(R.id.tvHeartRate);
tvSoundLevel = findViewById(R.id.tvSoundLevel);
btnScan.setOnClickListener(v -> {
if (!scanning) {
startScan();
} else {
stopScan();
}
});
}
private void setupBluetooth() {
bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager != null) {
bluetoothAdapter = bluetoothManager.getAdapter();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
}
}
private void checkPermissions() {
String[] permissions = {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT
};
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);
return;
}
}
}
@SuppressLint("MissingPermission")
private void startScan() {
if (bluetoothLeScanner != null) {
scanning = true;
btnScan.setText("Stop Scan");
bluetoothLeScanner.startScan(scanCallback);
handler.postDelayed(this::stopScan, 10000); // Stop scanning after 10 seconds
}
}
@SuppressLint("MissingPermission")
private void stopScan() {
if (bluetoothLeScanner != null) {
scanning = false;
btnScan.setText("Start Scan");
bluetoothLeScanner.stopScan(scanCallback);
}
}
private final ScanCallback scanCallback = new ScanCallback() {
@SuppressLint("MissingPermission")
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
if (DEVICE_NAME.equals(device.getName())) {
stopScan();
connectToDevice(device);
}
}
};
private void connectToDevice(BluetoothDevice device) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
bluetoothGatt = device.connectGatt(this, false, gattCallback);
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothGatt.STATE_CONNECTED) {
runOnUiThread(() -> tvConnectionStatus.setText("Status: Connected"));
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
bluetoothGatt.discoverServices();
} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
runOnUiThread(() -> tvConnectionStatus.setText("Status: Disconnected"));
}
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService service = gatt.getService(SERVICE_UUID);
if (service != null) {
BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHARACTERISTIC_UUID);
if (characteristic != null) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
gatt.setCharacteristicNotification(characteristic, true);
}
}
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
final String data = new String(characteristic.getValue());
parseAndUpdateUI(data);
}
}
};
private void parseAndUpdateUI(final String data) {
runOnUiThread(() -> {
try {
String[] sections = data.split(";");
for (String section : sections) {
String[] parts = section.split(":");
if (parts.length == 2) {
String type = parts[0];
String values = parts[1];
switch (type) {
case "ACC":
String[] accValues = values.split(",");
String accText = String.format("X: %.2f\nY: %.2f\nZ: %.2f",
Float.parseFloat(accValues[0]),
Float.parseFloat(accValues[1]),
Float.parseFloat(accValues[2]));
tvAccData.setText(accText);
break;
case "GYRO":
String[] gyroValues = values.split(",");
String gyroText = String.format("X: %.2f\nY: %.2f\nZ: %.2f",
Float.parseFloat(gyroValues[0]),
Float.parseFloat(gyroValues[1]),
Float.parseFloat(gyroValues[2]));
tvGyroData.setText(gyroText);
break;
case "HR":
tvHeartRate.setText(values + " BPM");
break;
case "SND":
tvSoundLevel.setText(String.format("%.2f V", Float.parseFloat(values)));
break;
}
}
}
} catch (Exception e) {
Toast.makeText(MainActivity.this, "Error parsing data", Toast.LENGTH_SHORT).show();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (bluetoothGatt != null) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
bluetoothGatt.close();
}
}
}
Манифест:
Это также есть в моем манифесте:
Я уже пытался спросить Клода или ChatGpt, потому что я ничего не знаю о протоколе BLE и у меня нет на это много времени из-за других моих занятий, пожалуйста, помогите мне
Подробнее здесь:
https://stackoverflow.com/questions/792 ... -android-s
1732481443
Anonymous
У меня есть проект, в котором я хочу прочитать данные датчика из ESP32C6 с помощью BLE 5.0 и я действительно запутался и не знаю, как кодировать настоящий BLE 5.0, но это мое задание. Не могли бы вы мне с этим помочь? Проблема: Я хочу прочитать данные датчика моего ESP32C6, но код Android Studio не подключается. с моим устройством и поэтому не обмениваюсь нужными мне данными и не отображаю их в моем приложении. Не могли бы вы мне с этим помочь? Код Arduino [code]#include #include #include #include #include #include #include "MAX30105.h" // Korrigierte Bibliothek #include "heartRate.h" // Zusätzliche Bibliothek für Herzfrequenzberechnung // BLE UUIDs #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" // Pin Definitions #define OPA344_PIN A0 // Task handles for core management TaskHandle_t Task1; TaskHandle_t Task2; // Mutex for protecting shared resources portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; SemaphoreHandle_t xMutex = NULL; // Sensor objects Adafruit_MPU6050 mpu; MAX30105 particleSensor; // Variables für Herzfrequenzberechnung const byte RATE_SIZE = 4; // Größe des Arrays für die Mittelwertbildung byte rates[RATE_SIZE]; // Array zur Speicherung der letzten Herzfrequenzen byte rateSpot = 0; long lastBeat = 0; // Zeit seit dem letzten Herzschlag float beatsPerMinute; int beatAvg; // BLE objects BLEServer* pServer = NULL; BLECharacteristic* pCharacteristic = NULL; bool deviceConnected = false; // Shared data structure struct SensorData { // MPU6050 data float accX, accY, accZ; float gyroX, gyroY, gyroZ; // MAX30102 data uint32_t red, ir; float heartRate; int avgHeartRate; // OPA344 data float soundLevel; } sensorData; class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; Serial.println("Device connected!"); } void onDisconnect(BLEServer* pServer) { deviceConnected = false; Serial.println("Device disconnected!"); } }; // Core 0: Sensor data acquisition void SensorTask(void * parameter) { for(;;) { if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) { // Read MPU6050 sensors_event_t a, g, temp; mpu.getEvent(&a, &g, &temp); sensorData.accX = a.acceleration.x; sensorData.accY = a.acceleration.y; sensorData.accZ = a.acceleration.z; sensorData.gyroX = g.gyro.x; sensorData.gyroY = g.gyro.y; sensorData.gyroZ = g.gyro.z; // Read MAX30102 and calculate heart rate sensorData.ir = particleSensor.getIR(); if (checkForBeat(sensorData.ir)) { long delta = millis() - lastBeat; lastBeat = millis(); beatsPerMinute = 60 / (delta / 1000.0); if (beatsPerMinute < 255 && beatsPerMinute > 20) { rates[rateSpot++] = (byte)beatsPerMinute; rateSpot %= RATE_SIZE; // Durchschnitt berechnen beatAvg = 0; for (byte x = 0; x < RATE_SIZE; x++) beatAvg += rates[x]; beatAvg /= RATE_SIZE; sensorData.heartRate = beatsPerMinute; sensorData.avgHeartRate = beatAvg; } } // Read OPA344 int rawValue = analogRead(OPA344_PIN); sensorData.soundLevel = (rawValue * 3.3) / 4095.0; xSemaphoreGive(xMutex); } vTaskDelay(pdMS_TO_TICKS(10)); // 100Hz sampling rate } } // Core 1: BLE and data processing void ProcessingTask(void * parameter) { for(;;) { if (deviceConnected && xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) { // Format data for BLE transmission String sensorDataStr = "ACC:" + String(sensorData.accX) + "," + String(sensorData.accY) + "," + String(sensorData.accZ) + ";GYRO:" + String(sensorData.gyroX) + "," + String(sensorData.gyroY) + "," + String(sensorData.gyroZ) + ";HR:" + String(sensorData.heartRate) + ";AVG_HR:" + String(sensorData.avgHeartRate) + ";SND:" + String(sensorData.soundLevel); // Send via BLE pCharacteristic->setValue(sensorDataStr.c_str()); pCharacteristic->notify(); xSemaphoreGive(xMutex); } vTaskDelay(pdMS_TO_TICKS(100)); // 10Hz update rate for BLE } } void setup() { Serial.begin(115200); Wire.begin(); // Create mutex xMutex = xSemaphoreCreateMutex(); // Initialize MPU6050 if (!mpu.begin()) { Serial.println("MPU6050 not found!"); while (1) delay(10); } mpu.setAccelerometerRange(MPU6050_RANGE_8_G); mpu.setGyroRange(MPU6050_RANGE_500_DEG); mpu.setFilterBandwidth(MPU6050_BAND_21_HZ); // Initialize MAX30102 if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) { Serial.println("MAX30102 not found!"); while (1) delay(10); } // Konfiguration für den MAX30102 particleSensor.setup(); particleSensor.setPulseAmplitudeRed(0x0A); particleSensor.setPulseAmplitudeGreen(0); particleSensor.setPulseAmplitudeIR(0x0A); particleSensor.setSampleRate(200); // Setzt die Sample Rate auf 200Hz particleSensor.setFIFOAverage(4); // Setzt den Durchschnitt auf 4 Samples // Initialize BLE BLEDevice::init("ESP32C6"); pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); BLEService *pService = pServer->createService(SERVICE_UUID); pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY ); pService->start(); BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); pAdvertising->setMaxPreferred(0x12); BLEDevice::startAdvertising(); // Create tasks for each core xTaskCreatePinnedToCore( SensorTask, // Task function "SensorTask", // Name 10000, // Stack size NULL, // Parameters 1, // Priority &Task1, // Task handle 0 // Core ID (0) ); xTaskCreatePinnedToCore( ProcessingTask, "ProcessingTask", 10000, NULL, 1, &Task2, 1 // Core ID (1) ); Serial.println("Setup complete!"); } void loop() { // Empty loop as tasks handle all the work vTaskDelay(pdMS_TO_TICKS(1000)); } [/code] Код Android Studio: [code]package com.example.project; import android.Manifest; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanResult; import android.content.Context; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import java.util.UUID; public class MainActivity extends AppCompatActivity { private static final int PERMISSION_REQUEST_CODE = 1; private static final String DEVICE_NAME = "ESP32C6"; private static final UUID SERVICE_UUID = UUID.fromString("4fafc201-1fb5-459e-8fcc-c5c9c331914b"); private static final UUID CHARACTERISTIC_UUID = UUID.fromString("beb5483e-36e1-4688-b7f5-ea07361b26a8"); private BluetoothManager bluetoothManager; private BluetoothAdapter bluetoothAdapter; private BluetoothLeScanner bluetoothLeScanner; private BluetoothGatt bluetoothGatt; private Button btnScan; private TextView tvConnectionStatus, tvAccData, tvGyroData, tvHeartRate, tvSoundLevel; private boolean scanning = false; private Handler handler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initializeViews(); setupBluetooth(); checkPermissions(); } private void initializeViews() { btnScan = findViewById(R.id.btnScan); tvConnectionStatus = findViewById(R.id.tvConnectionStatus); tvAccData = findViewById(R.id.tvAccData); tvGyroData = findViewById(R.id.tvGyroData); tvHeartRate = findViewById(R.id.tvHeartRate); tvSoundLevel = findViewById(R.id.tvSoundLevel); btnScan.setOnClickListener(v -> { if (!scanning) { startScan(); } else { stopScan(); } }); } private void setupBluetooth() { bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (bluetoothManager != null) { bluetoothAdapter = bluetoothManager.getAdapter(); bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); } } private void checkPermissions() { String[] permissions = { Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT }; for (String permission : permissions) { if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE); return; } } } @SuppressLint("MissingPermission") private void startScan() { if (bluetoothLeScanner != null) { scanning = true; btnScan.setText("Stop Scan"); bluetoothLeScanner.startScan(scanCallback); handler.postDelayed(this::stopScan, 10000); // Stop scanning after 10 seconds } } @SuppressLint("MissingPermission") private void stopScan() { if (bluetoothLeScanner != null) { scanning = false; btnScan.setText("Start Scan"); bluetoothLeScanner.stopScan(scanCallback); } } private final ScanCallback scanCallback = new ScanCallback() { @SuppressLint("MissingPermission") @Override public void onScanResult(int callbackType, ScanResult result) { BluetoothDevice device = result.getDevice(); if (DEVICE_NAME.equals(device.getName())) { stopScan(); connectToDevice(device); } } }; private void connectToDevice(BluetoothDevice device) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { return; } bluetoothGatt = device.connectGatt(this, false, gattCallback); } private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (status == BluetoothGatt.GATT_SUCCESS) { if (newState == BluetoothGatt.STATE_CONNECTED) { runOnUiThread(() -> tvConnectionStatus.setText("Status: Connected")); if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { return; } bluetoothGatt.discoverServices(); } else if (newState == BluetoothGatt.STATE_DISCONNECTED) { runOnUiThread(() -> tvConnectionStatus.setText("Status: Disconnected")); } } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { BluetoothGattService service = gatt.getService(SERVICE_UUID); if (service != null) { BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHARACTERISTIC_UUID); if (characteristic != null) { if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { return; } gatt.setCharacteristicNotification(characteristic, true); } } } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { if (CHARACTERISTIC_UUID.equals(characteristic.getUuid())) { final String data = new String(characteristic.getValue()); parseAndUpdateUI(data); } } }; private void parseAndUpdateUI(final String data) { runOnUiThread(() -> { try { String[] sections = data.split(";"); for (String section : sections) { String[] parts = section.split(":"); if (parts.length == 2) { String type = parts[0]; String values = parts[1]; switch (type) { case "ACC": String[] accValues = values.split(","); String accText = String.format("X: %.2f\nY: %.2f\nZ: %.2f", Float.parseFloat(accValues[0]), Float.parseFloat(accValues[1]), Float.parseFloat(accValues[2])); tvAccData.setText(accText); break; case "GYRO": String[] gyroValues = values.split(","); String gyroText = String.format("X: %.2f\nY: %.2f\nZ: %.2f", Float.parseFloat(gyroValues[0]), Float.parseFloat(gyroValues[1]), Float.parseFloat(gyroValues[2])); tvGyroData.setText(gyroText); break; case "HR": tvHeartRate.setText(values + " BPM"); break; case "SND": tvSoundLevel.setText(String.format("%.2f V", Float.parseFloat(values))); break; } } } } catch (Exception e) { Toast.makeText(MainActivity.this, "Error parsing data", Toast.LENGTH_SHORT).show(); } }); } @Override protected void onDestroy() { super.onDestroy(); if (bluetoothGatt != null) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { return; } bluetoothGatt.close(); } } } [/code] Манифест: Это также есть в моем манифесте: [code] [/code] Я уже пытался спросить Клода или ChatGpt, потому что я ничего не знаю о протоколе BLE и у меня нет на это много времени из-за других моих занятий, пожалуйста, помогите мне Подробнее здесь: [url]https://stackoverflow.com/questions/79221064/exchanging-sensor-data-of-an-esp32c6-with-ble-5-0-per-arduino-code-and-android-s[/url]