ESP32 Arduino 蓝牙低功耗深度睡眠技术

4
我正在处理涉及两个ESP32 Wemos D1 Mini板的项目。我正在使用BLE功能将传感器读数从“服务器”传输到“客户端”。我向客户端使用Characteristic Notify来接收传感器读数。如果我想在服务器上实现深度睡眠功能,客户端会发生什么?客户端是否也必须在某个时刻重置? 此外,在深度睡眠场景中使用Characteristic.Notify是否明智?
谢谢。
服务器代码:
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include "DHT.h"

#define DHTPIN 4
#define DHTTYPE DHT22
#define uS_TO_S_FACTOR 1000000  //Conversion factor for micro seconds to seconds
#define TIME_TO_SLEEP  15        //Time ESP32 will go to sleep (in seconds)

RTC_DATA_ATTR int bootCount = 0;
DHT dht(DHTPIN, DHTTYPE);
BLECharacteristic *pCharacteristic;

bool deviceConnected = false;
uint8_t txValue = 50;

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

//Function that prints the reason by which ESP32 has been awaken from sleep
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();
  switch(wakeup_reason)
  {
    case 1  : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case 2  : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case 3  : Serial.println("Wakeup caused by timer"); break;
    case 4  : Serial.println("Wakeup caused by touchpad"); break;
    case 5  : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.println("Wakeup was not caused by deep sleep"); break;
  }
}

void setup() {
  Serial.begin(115200);

  Serial.println(F("initating DHT22..."));
  dht.begin();

  // Create the BLE Device
  BLEDevice::init("UART"); // Name must not be longer than 5 chars!!!

  // Create the BLE Server
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_TX,
                      BLECharacteristic::PROPERTY_NOTIFY|BLECharacteristic::PROPERTY_READ|BLECharacteristic::PROPERTY_WRITE
                    );

  BLE2902 *desc = new BLE2902();
  desc->setNotifications(true);
  pCharacteristic->addDescriptor(desc);

  // Start the service
  pService->start();
  pServer->getAdvertising()->addServiceUUID(SERVICE_UUID);
  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println(pService->getUUID().toString().c_str());
  Serial.println("Waiting a client connection to notify...");

  if (deviceConnected) {

    float f = dht.readTemperature(true);
    char fStr[10];
    sprintf(fStr, "%4.4f", f);

    Serial.print("Temperature reading: ");
    Serial.println(fStr);

    Serial.printf("*** Sent Value: %d ***\n", fStr);
    pCharacteristic->setValue(fStr);

    pCharacteristic->notify();

    //Set timer to 5 seconds
    esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
    Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
    " Seconds");

    //Go to sleep now
    esp_deep_sleep_start();

  }
  //delay(60000);
}

void loop() {}

客户端代码:

#include "BLEDevice.h"
#include <WiFi.h>

// The remote service we wish to connect to.
static BLEUUID serviceUUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
static BLEUUID    charUUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");

static BLEAddress *pServerAddress;
static boolean doConnect = false;
static boolean connected = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;

const char* ssid     = "Kings";
const char* password = "GoCanada";
const char* host = "menezes-service.herokuapp.com";
WiFiClient client;

static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
    Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
    Serial.print(" of data length ");
    Serial.println(length);
    //std::string value = pBLERemoteCharacteristic->readValue();
    byte buffer[42];
    Serial.print("The characteristic value sent was: ");
    //Serial.println(pBLERemoteCharacteristic->readValue().c_str());
    //Serial.println(pBLERemoteCharacteristic->readUInt8());
    std::string farhenheight = pRemoteCharacteristic->readValue();
    Serial.print("Farheinheight: ");
    Serial.println(farhenheight.c_str());
    Serial.println(F("Posting to api!"));
    Serial.println();
    Serial.println("closing connection");
}

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
    Serial.println("connected again ... ");
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
  }
};

bool connectToServer(BLEAddress pAddress) {
    Serial.print("Forming a connection to ");
    Serial.println(pAddress.toString().c_str());

    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient->setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient->connect(pAddress);
    Serial.println(" - Connected to server");

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
    Serial.println(pRemoteService->toString().c_str());
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(serviceUUID.toString().c_str());
      return false;
    }
    Serial.println(" - Found our service");

    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
    if (pRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charUUID.toString().c_str());
      return false;
    }
    Serial.println(" - Found our characteristic");

    pRemoteCharacteristic->registerForNotify(notifyCallback);
}

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.print("BLE Advertised Device found: ");
    Serial.println(advertisedDevice.toString().c_str());
    //Serial.print(advertisedDevice.haveServiceUUID());

    if(advertisedDevice.haveServiceUUID()){
      Serial.println(advertisedDevice.getServiceUUID().toString().c_str());
    }


    // We have found a device, let us now see if it contains the service we are looking for.
    if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(serviceUUID)) {

      // 
      Serial.print("Found our device!  address: "); 
      advertisedDevice.getScan()->stop();

      pServerAddress = new BLEAddress(advertisedDevice.getAddress());
      doConnect = true;

    } // Found our server

  } // onResult
}; // MyAdvertisedDeviceCallbacks

void setup() {
  Serial.begin(115200);
  Serial.println("Starting Arduino BLE Client application...");
  BLEDevice::init("");
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  pBLEScan->start(30);

} // End of setup.

// This is the Arduino main loop function.
void loop() {
  if (doConnect == true) {
    if (connectToServer(*pServerAddress)) {
        Serial.println("We are now connected to the BLE Server.");
        connected = true;
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    //doConnect = false;
  }

  if (connected == false){
    BLEDevice::getScan()->start(0);
  }
  else{
    doConnect = false;
  }

  delay(1000); // Delay a second between loops.
} // End of loop
1个回答

3
请查看以下关于您问题的回答:-
如果我想要在服务器上实现深度睡眠功能,客户端会发生什么?客户端是否也必须在某个时候重置?
不,客户端不需要重置,但是您可能需要重新连接到服务器,因为在深度睡眠中,BLE连接会丢失。如果您希望在服务器唤醒时自动建立连接,则必须更新客户端代码,以便它持续尝试重新连接到服务器。这样,当服务器唤醒时,客户端将连接到它并继续接收通知。
此外,在深度睡眠场景中使用Characteristic.Notify是否明智?
在深度睡眠中,CPU将关闭,因此您将无法在此状态下发送通知。在此模式下,您只能通过定时器或外部外设(例如触摸引脚)唤醒CPU。有关更多信息,请参见下面的链接:-

我希望这可以帮助到你。


感谢您的评论,Youssif。我发现当客户端在服务器重新启动后重新连接时,“notifyCallBack”处理程序方法从未运行。我无法捕获新发送的值。所以我想知道,在重置后是否必须从服务器运行“Notify”?我尝试过没有它,但是卡住了..有什么想法吗? - Kevin M.
你有收到任何错误吗?你可能需要重新启用来自中央端的通知,就像你在进入睡眠模式之前所做的那样。 - Youssif Saeed
谢谢。在实现睡眠功能之前,我已经在服务器的void loop()中运行了通知。 - Kevin M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接