【搬运】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
有试成功的吗?
实测是可以的。就是看时间这个功能很鸡肋,是不定时出现一下时间。
即当你想看时间,得等上几十秒才可能看到。
页:
[1]