【搬运】iPhone watch OR StickC band?-Arduino中文社区 - Powered by Discuz! Archiver

vany5921 发表于 2019-9-29 11:50

【搬运】iPhone watch OR StickC band?

    原文地址:https://www.hackster.io/takeru/notifications-from-iphone-to-esp32-watch-251a6e 作者 takeru      

    【简介】本项目利用StickC制作一个智能手环,通过BLE与iphone进行连接,M5StickC的屏幕可以显示时间、来电通知
   使用方法:打开iPhone的蓝牙设置。查找名为“ Watch”的设备。选择它并进行配对。此后,将要求您允许“监视”使用通知数据。如果您有通知。每10秒StickC发出红色LED通知。如果有电话接入,LED将闪烁并在显示屏上显示“ Calling ..”。如果手环远离iPhone(BLE连接丢失),Watch将在LED和显示屏上提醒您。不要忘记手环的最基本功能,您可以看到现在几点了。
#include <Arduino.h>
#include "BLEDevice.h"
#include "BLEServer.h"
#include "BLEClient.h"
#include "BLEUtils.h"
#include "BLE2902.h"
#include <esp_log.h>
#include <esp_bt_main.h>
#include <string>
#include "Task.h"
#include <sys/time.h>
#include <time.h>
#include "sdkconfig.h"
#include <M5StickC.h>

static char LOG_TAG[] = "SampleServer";

static BLEUUID ancsServiceUUID("7905F431-B5CE-4E99-A40F-4B1E122D00D0");
static BLEUUID notificationSourceCharacteristicUUID("9FBF120D-6301-42D9-8C58-25E699A21DBD");
static BLEUUID controlPointCharacteristicUUID("69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9");
static BLEUUID dataSourceCharacteristicUUID("22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB");

class MySecurity : public BLESecurityCallbacks {

    uint32_t onPassKeyRequest(){
      ESP_LOGI(LOG_TAG, "PassKeyRequest");
      return 123456;
    }

    void onPassKeyNotify(uint32_t pass_key){
      ESP_LOGI(LOG_TAG, "On passkey Notify number:%d", pass_key);
    }

    bool onSecurityRequest(){
      ESP_LOGI(LOG_TAG, "On Security Request");
      return true;
    }
   
    bool onConfirmPIN(unsigned int){
      ESP_LOGI(LOG_TAG, "On Confrimed Pin Request");
      return true;
    }

    void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl){
      ESP_LOGI(LOG_TAG, "Starting BLE work!");
      if(cmpl.success){
            uint16_t length;
            esp_ble_gap_get_whitelist_size(&length);
            ESP_LOGD(LOG_TAG, "size: %d", length);
      }
    }
};

bool connected = false;

#define CATEGORY_TABLE_SIZE 12
int notification_counts = {0,0,0,0,0,0,0,0,0,0,0,0};
char* category_table = {
"Other",         //0
"Incoming call", //1
"Missed call",   //2
"Voicemail",   //3
"Social",      //4
"Schedule",      //5
"Email",         //6
"News",          //7
"Health",      //8
"Business",      //9
"Location",      // 10
"Entertainment", // 11
};
#define CATEGORY_INCOMING_CALL 1

static void _dataSourceNotifyCallback(BLERemoteCharacteristic* pCharacteristic, uint8_t* pData, size_t length, bool isNotify);
static void _notificationSourceNotifyCallback(BLERemoteCharacteristic* pCharacteristic, uint8_t* pData, size_t length, bool isNotify);

/**
* Become a BLE client to a remote BLE server.We are passed in the address of the BLE server
* as the input parameter when the task is created.
*/
class MyClient: public Task {
    void run(void* data) {

      BLEAddress* pAddress = (BLEAddress*)data;
      BLEClient*pClient= BLEDevice::createClient();
      BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
      BLEDevice::setSecurityCallbacks(new MySecurity());

      BLESecurity *pSecurity = new BLESecurity();
      pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
      pSecurity->setCapability(ESP_IO_CAP_IO);
      pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
      // Connect to the remove BLE Server.
      pClient->connect(*pAddress);

      /** BEGIN ANCS SERVICE **/
      // Obtain a reference to the service we are after in the remote BLE server.
      BLERemoteService* pAncsService = pClient->getService(ancsServiceUUID);
      if (pAncsService == nullptr) {
            ESP_LOGD(LOG_TAG, "Failed to find our service UUID: %s", ancsServiceUUID.toString().c_str());
            return;
      }
      // Obtain a reference to the characteristic in the service of the remote BLE server.
      BLERemoteCharacteristic* pNotificationSourceCharacteristic = pAncsService->getCharacteristic(notificationSourceCharacteristicUUID);
      if (pNotificationSourceCharacteristic == nullptr) {
            ESP_LOGD(LOG_TAG, "Failed to find our characteristic UUID: %s", notificationSourceCharacteristicUUID.toString().c_str());
            return;
      }      
      // Obtain a reference to the characteristic in the service of the remote BLE server.
      BLERemoteCharacteristic* pControlPointCharacteristic = pAncsService->getCharacteristic(controlPointCharacteristicUUID);
      if (pControlPointCharacteristic == nullptr) {
            ESP_LOGD(LOG_TAG, "Failed to find our characteristic UUID: %s", controlPointCharacteristicUUID.toString().c_str());
            return;
      }      
      // Obtain a reference to the characteristic in the service of the remote BLE server.
      BLERemoteCharacteristic* pDataSourceCharacteristic = pAncsService->getCharacteristic(dataSourceCharacteristicUUID);
      if (pDataSourceCharacteristic == nullptr) {
            ESP_LOGD(LOG_TAG, "Failed to find our characteristic UUID: %s", dataSourceCharacteristicUUID.toString().c_str());
            return;
      }      
      const uint8_t v[]={0x1,0x0};
      pDataSourceCharacteristic->registerForNotify(_dataSourceNotifyCallback);
      pDataSourceCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)v,2,true);
      pNotificationSourceCharacteristic->registerForNotify(_notificationSourceNotifyCallback);
      pNotificationSourceCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)v,2,true);
      /** END ANCS SERVICE **/
    } // run

    public:
    void dataSourceNotifyCallback(BLERemoteCharacteristic* pCharacteristic, uint8_t* pData, size_t length, bool isNotify){
      Serial.print("Notify callback for characteristic ");
      Serial.print(pCharacteristic->getUUID().toString().c_str());
      Serial.print(" of data length ");
      Serial.println(length);
    }

    public:
    void notificationSourceNotifyCallback(BLERemoteCharacteristic* pCharacteristic, uint8_t* pData, size_t length, bool isNotify){
      if(pData==0){
      uint8_t category_id = pData;
      notification_counts++;
      Serial.printf("New notification! Category: %s(%d) count=%d\n", category_table, category_id, notification_counts);
      }else
      if(pData==1){
      Serial.printf("Notification modified!\n");
      }else
      if(pData==2){
      uint8_t category_id = pData;
      notification_counts--;
      Serial.printf("Notification removed! Category: %s(%d) count=%d\n", category_table, category_id, notification_counts);
      }
      Serial.printf("pData=");
      for(int i=0; i<length; i++){
      Serial.printf("%02X ", pData);
      }
      Serial.printf("length=%d isNotify=%d\n", length, isNotify);
    }
}; // MyClient

MyClient* pMyClient = NULL; // only one instance....
static void _dataSourceNotifyCallback(BLERemoteCharacteristic* pCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
    pMyClient->dataSourceNotifyCallback(pCharacteristic, pData, length, isNotify);
}
static void _notificationSourceNotifyCallback(BLERemoteCharacteristic* pCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
    pMyClient->notificationSourceNotifyCallback(pCharacteristic, pData, length, isNotify);
}


class MainBLEServer: public Task, public BLEServerCallbacks {
    void run(void *data) {
      ESP_LOGD(LOG_TAG, "Starting BLE work!");
      esp_log_buffer_char(LOG_TAG, LOG_TAG, sizeof(LOG_TAG));
      esp_log_buffer_hex(LOG_TAG, LOG_TAG, sizeof(LOG_TAG));

      // Initialize device
      BLEDevice::init("Watch");
      BLEServer* pServer = BLEDevice::createServer();
      pServer->setCallbacks(this);
      BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
      BLEDevice::setSecurityCallbacks(new MySecurity());

      // Advertising parameters:
      // Soliciting ANCS
      BLEAdvertising *pAdvertising = pServer->getAdvertising();
      BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
      oAdvertisementData.setFlags(0x01);
      _setServiceSolicitation(&oAdvertisementData, BLEUUID("7905F431-B5CE-4E99-A40F-4B1E122D00D0"));
      pAdvertising->setAdvertisementData(oAdvertisementData);      

      // Set security
      BLESecurity *pSecurity = new BLESecurity();
      pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
      pSecurity->setCapability(ESP_IO_CAP_OUT);
      pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);

      //Start advertising
      pAdvertising->start();
      
      ESP_LOGD(LOG_TAG, "Advertising started!");
      delay(portMAX_DELAY);
    }

    void onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param) {
      Serial.println("********************");
      Serial.println("**Device connected**");
      Serial.println(BLEAddress(param->connect.remote_bda).toString().c_str());
      Serial.println("********************");
      if(pMyClient != NULL){
          Serial.println("...invalid state...");
          return;
      }
      pMyClient = new MyClient();
      pMyClient->setStackSize(18000);
      pMyClient->start(new BLEAddress(param->connect.remote_bda));
      connected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      Serial.println("************************");
      Serial.println("**Devicedisconnected**");
      Serial.println("************************");

      // reboot
      M5.Axp.DeepSleep(SLEEP_SEC(1));
    }

    /**
   * @brief Set the service solicitation (UUID)
   * @param uuid The UUID to set with the service solicitation data.Size of UUID will be used.
   */
    void _setServiceSolicitation(BLEAdvertisementData *a, BLEUUID uuid)
    {
      char cdata;
      switch(uuid.bitSize()) {
      case 16: {
          // data
          cdata = 3;
          cdata = ESP_BLE_AD_TYPE_SOL_SRV_UUID;// 0x14
          a->addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid16,2));
          break;
      }
   
      case 128: {
          // data
          cdata = 17;
          cdata = ESP_BLE_AD_TYPE_128SOL_SRV_UUID;// 0x15
          a->addData(std::string(cdata, 2) + std::string((char *)uuid.getNative()->uuid.uuid128,16));
          break;
      }
   
      default:
          return;
      }
    } // setServiceSolicitationData

   
};

void SampleSecureServer(void)
{
    MainBLEServer* pMainBleServer = new MainBLEServer();
    pMainBleServer->setStackSize(20000);
    pMainBleServer->start();
}


#define LED_BUILTIN 10

void setup()
{
M5.begin(false);
M5.Axp.ScreenBreath(7);
M5.Lcd.begin();

M5.Lcd.fillScreen(BLACK);
M5.Lcd.setRotation(1);
M5.Lcd.setTextFont(1);

pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
pinMode(M5_BUTTON_HOME, INPUT);

Serial.begin(115200);
SampleSecureServer();
}

void loop()
{
bool led = false;
int toral_count = 0;
for(int i=0; i<CATEGORY_TABLE_SIZE; i++){
    toral_count += notification_counts;
}
if(!connected && 3*1000 < millis()){
    led = (millis() / 200 % 2 == 0);
}else
if(0 < notification_counts){
    led = (millis() / 100 % 2 == 0);
}else
if(0 < toral_count){
    led = (millis() / 100 % 100 == 0);
}else{
    led = false;
}
digitalWrite(LED_BUILTIN, led ? LOW : HIGH);
display();
delay(20);
}


void display()
{
static int last_counter = 0;
int counter = millis() / 100;
if(counter == last_counter){ return; }
last_counter = counter;

if(!connected && 3*1000 < millis()){
    uint16_t c0 = YELLOW;
    uint16_t c1 = RED;
    switch(counter / 3 % 2){
    case 0:
      c0 = YELLOW;
      c1 = RED;
      break;
    case 1:
      c0 = RED;
      c1 = YELLOW;
      break;
    }
    M5.Axp.ScreenBreath(15);
    M5.Lcd.fillScreen(c1);
    M5.Lcd.setTextSize(4);
    M5.Lcd.setCursor(3, 3, 1);
    M5.Lcd.setTextColor(c0, c1);
    M5.Lcd.printf("Misplaced!?");
}else
if(0 < notification_counts){
    switch(counter / 10 % 2){
    case 0:
      M5.Axp.ScreenBreath(15);
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setTextSize(4);
      M5.Lcd.setCursor(3, 3, 1);
      M5.Lcd.setTextColor(GREEN, BLACK);
      M5.Lcd.printf("Calling...");
      break;
    case 1:
      M5.Axp.ScreenBreath(0);
      M5.Lcd.fillScreen(BLACK);
      break;
    }
}else{
    RTC_TimeTypeDef RTC_TimeStruct;
    M5.Rtc.GetTime(&RTC_TimeStruct);
    if(RTC_TimeStruct.Seconds <= 5){
      if(RTC_TimeStruct.Minutes == 0){
      M5.Axp.ScreenBreath(15);
      }else
      if(RTC_TimeStruct.Minutes % 15 == 0){
      M5.Axp.ScreenBreath(12);
      }else{
      M5.Axp.ScreenBreath(8);
      }
      RTC_DateTypeDef RTC_DateStruct;
      M5.Rtc.GetData(&RTC_DateStruct);
      M5.Lcd.setCursor(3, 3, 7);
      M5.Lcd.setTextSize(1);
      M5.Lcd.setTextColor(ORANGE, BLACK);
      M5.Lcd.printf("%02d:%02d", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes);
      Serial.printf("%04d-%02d-%02d(%d) %02d:%02d:%02d\n", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date, RTC_DateStruct.WeekDay, RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);
    }else{
      M5.Axp.ScreenBreath(0);
      M5.Lcd.fillScreen(BLACK);
    }
}
}



laai 发表于 2020-2-28 23:24

有试成功的吗?

laai 发表于 2020-3-12 00:38

laai 发表于 2020-2-28 23:24
有试成功的吗?

实测是可以的。就是看时间这个功能很鸡肋,是不定时出现一下时间。
即当你想看时间,得等上几十秒才可能看到。
页: [1]
查看完整版本: 【搬运】iPhone watch OR StickC band?