0


Unity3D蓝牙连接Mi Band 5手环获取实时心率

Unity3D蓝牙连接Mi Band 5手环获取实时心率
直接上代码

using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;publicclassBLEMiBand:MonoBehaviour{publicclassUUIDS{publicstaticreadonlystring miband1 ="0000fee0-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring miband2 ="0000fee1-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring alert ="00001802-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring devinfo ="0000180a-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring heartrate ="0000180d-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring notifications ="00001811-0000-1000-8000-00805f9b34fb";}publicclassCHAR_UUIDS{publicstaticreadonlystring devicename ="00002a00-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring hz ="00000002-0000-3512-2118-0009af100700";publicstaticreadonlystring sensor ="00000001-0000-3512-2118-0009af100700";publicstaticreadonlystring auth ="00000009-0000-3512-2118-0009af100700";publicstaticreadonlystring alert ="00002a06-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring current_time ="00002a2b-0000-1000-8000-00805f9b34fb";// unknown=         "00002a23-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring serial ="00002a25-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring hrdw_revision ="00002a27-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring revision ="00002a28-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring heartrate_measure ="00002a37-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring heartrate_control ="00002a39-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring notifications ="00002a46-0000-1000-8000-00805f9b34fb";// unknown=         "00002a50-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring age ="00002a80-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring le_params ="0000ff09-0000-1000-8000-00805f9b34fb";publicstaticreadonlystring configuration ="00000003-0000-3512-2118-0009af100700";publicstaticreadonlystring fetch ="00000004-0000-3512-2118-0009af100700";publicstaticreadonlystring activity_data ="00000005-0000-3512-2118-0009af100700";publicstaticreadonlystring battery ="00000006-0000-3512-2118-0009af100700";publicstaticreadonlystring steps ="00000007-0000-3512-2118-0009af100700";publicstaticreadonlystring user_settings ="00000008-0000-3512-2118-0009af100700";publicstaticreadonlystring music_notification ="00000010-0000-3512-2118-0009af100700";publicstaticreadonlystring deviceevent ="00000010-0000-3512-2118-0009af100700";publicstaticreadonlystring chunked_transfer ="00000020-0000-3512-2118-0009af100700";}publicclassNOTIFICATION_TYPES{publicstaticreadonlybyte[] auth ={0x02,0x00};publicstaticreadonlybyte[] msg ={0x01,0x01};publicstaticreadonlybyte[] call ={0x03,0x01};publicstaticreadonlybyte[] missed ={0x04,0x01};publicstaticreadonlybyte[] sms ={0x05,0x01};}publicclassAUTH_TYPES{publicstaticreadonlybyte[] received ={0x10,0x01,0x01};publicstaticreadonlybyte[] requestcode ={0x10,0x02,0x01};publicstaticreadonlybyte[] authed ={0x10,0x03,0x01};publicstaticreadonlybyte[] authfail ={0x10,0x03,0x08};}publicclassHEARTRATECONTROL_TYPES{publicstaticreadonlybyte[] stop_heartrate_manual ={0x15,0x01,0x00};publicstaticreadonlybyte[] stop_heartrate_auto ={0x15,0x02,0x00};publicstaticreadonlybyte[] start_heartrate_manual ={0x15,0x01,0x01};publicstaticreadonlybyte[] start_heartrate_auto ={0x15,0x02,0x01};publicstaticreadonlybyte[] ping ={0x16};}publicstring DeviceName ="Mi Smart Band 5";publicstring AuthKey ="50a2c4668b3e565c0f495885251c4346";publicText txtMiBandLabel;publicText txtMiBandStatus;publicText txtBluetoothStatus;publicGameObject PanelMiddle;publicText txtHeartRate;enum States
  {
    None,
    Scan,
    Connect,
    Auth,
    Subscribe,
    Unsubscribe,
    Disconnect,
    Communication,}[SerializeField]privatebool bConnected =false;[SerializeField]privatebool bAuthed =false;[SerializeField]privatebool bSubscribed =false;[SerializeField]privatestring device;[SerializeField]bool foundChartAuth =false;[SerializeField]bool foundChartHeartrateControl =false;[SerializeField]bool foundChartHeartrateMeasurement =false;[SerializeField]bool foundChartSensor =false;voidReset(){
    bConnected =false;
    bAuthed =false;
    device =null;
    foundChartAuth =false;
    foundChartHeartrateControl =false;
    foundChartHeartrateMeasurement =false;
    foundChartSensor =false;
    PanelMiddle.SetActive(false);}voidInitBLE(){
    txtMiBandStatus.text ="";
    txtBluetoothStatus.text ="Initializing...";Reset();
    BluetoothLEHardwareInterface.Initialize(true,false,()=>{StartCoroutine(delayScan(0.1f));
      txtBluetoothStatus.text ="Initialized";},(error)=>{
      BluetoothLEHardwareInterface.Log("Error: "+ error);});}// Use this for initializationvoidStart(){InitBLE();}// Update is called once per framevoidUpdate(){}IEnumeratordelayScan(float delay){yieldreturnnewWaitForSeconds(delay);
    txtBluetoothStatus.text ="Scanning devices["+ DeviceName +"]";

    BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null,(address, name)=>{// we only want to look at devices that have the name we are looking for// this is the best way to filter out devicesif(name.Contains(DeviceName)){
        DeviceName = name;// it is always a good idea to stop scanning while you connect to a device// and get things set up
        BluetoothLEHardwareInterface.StopScan();
        txtBluetoothStatus.text ="";// add it to the list and set to connect to it
        device = address;

        txtMiBandLabel.text = DeviceName +"["+ device +"]";
        txtMiBandStatus.text ="Found "+ DeviceName;StartCoroutine(delayConnect(0.5f));}},null,false,false);}IEnumeratordelayConnect(float delay){yieldreturnnewWaitForSeconds(delay);// set these flags
    txtMiBandStatus.text ="Connecting to "+ DeviceName;// note that the first parameter is the address, not the name. I have not fixed this because// of backwards compatiblity.// also note that I am note using the first 2 callbacks. If you are not looking for specific characteristics you can use one of// the first 2, but keep in mind that the device will enumerate everything and so you will want to have a timeout// large enough that it will be finished enumerating before you try to subscribe or do any other operations.
    BluetoothLEHardwareInterface.ConnectToPeripheral(device,null,null,(address, serviceUUID, characteristicUUID)=>{if(IsEqual(serviceUUID, UUIDS.miband2)&&IsEqual(characteristicUUID, CHAR_UUIDS.auth)){
        foundChartAuth =true;}elseif(IsEqual(serviceUUID, UUIDS.heartrate)&&IsEqual(characteristicUUID, CHAR_UUIDS.heartrate_control)){
        foundChartHeartrateControl =true;}elseif(IsEqual(serviceUUID, UUIDS.heartrate)&&IsEqual(characteristicUUID, CHAR_UUIDS.heartrate_measure)){
        foundChartHeartrateMeasurement =true;}elseif(IsEqual(serviceUUID, UUIDS.miband1)&&IsEqual(characteristicUUID, CHAR_UUIDS.sensor)){
        foundChartSensor =true;}// all need characteristics foundif(foundChartAuth && foundChartHeartrateControl && foundChartHeartrateMeasurement && foundChartSensor){
        bConnected =true;
        txtMiBandStatus.text ="Connected to "+ DeviceName;// if we have found the characteristic that we are waiting for// authenticate. make sure there is enough timeout that if the// device is still enumerating other characteristics it finishes// before we try to subscribeStartCoroutine(delayAuthenticate(12f));}},(disconnectedAddress)=>{
      BluetoothLEHardwareInterface.Log("Device disconnected: "+ disconnectedAddress);
      txtMiBandStatus.text ="Disconnected";
      bConnected =false;
      bAuthed =false;
      bSubscribed =false;});}IEnumeratordelayAuthenticate(float delay){
    PanelMiddle.SetActive(true);yieldreturnnewWaitForSeconds(delay);SubscribeAuth();yieldreturnnewWaitForSeconds(0.5f);SendAuth();}IEnumeratordelaySubscribeHeartrate(float delay){yieldreturnnewWaitForSeconds(delay);
    BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_control,
      HEARTRATECONTROL_TYPES.stop_heartrate_auto, HEARTRATECONTROL_TYPES.stop_heartrate_auto.Length,false,(charUUID)=>{});yieldreturnnewWaitForSeconds(0.5f);
    BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_control,
      HEARTRATECONTROL_TYPES.stop_heartrate_manual, HEARTRATECONTROL_TYPES.stop_heartrate_manual.Length,false,(charUUID)=>{});yieldreturnnewWaitForSeconds(0.5f);
    BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_measure,null,(address, characteristicUUID, bytes)=>{
      txtMiBandStatus.text ="Received Subscribe["+ bytes.Length.ToString()+"]["+ Time.time.ToString("F2")+"]"+ Utility.Bytes2Hex(bytes)+"";if(2== bytes.Length){byte[] heartrate ={ bytes[1], bytes[0]};
        txtHeartRate.text = System.BitConverter.ToInt16(heartrate,0).ToString("D3")+"BPM";}elseif(1== bytes.Length){
        txtHeartRate.text =((int)(bytes[0])).ToString("D3")+"BPM";}});yieldreturnnewWaitForSeconds(0.5f);
    txtMiBandStatus.text ="Starting manual heart rate detection...";
    BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_control,
      HEARTRATECONTROL_TYPES.start_heartrate_manual, HEARTRATECONTROL_TYPES.start_heartrate_manual.Length,false,(charUUID)=>{
        txtMiBandStatus.text ="Startedmanual heart rate detection...";});while(bSubscribed){yieldreturnnewWaitForSeconds(12f);
      BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_control,
        HEARTRATECONTROL_TYPES.ping, HEARTRATECONTROL_TYPES.ping.Length,false,(charUUID)=>{});}}IEnumeratordelayUnsubscribeHeartrate(float delay){yieldreturnnewWaitForSeconds(delay);
    BluetoothLEHardwareInterface.UnSubscribeCharacteristic(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_measure,null);
    bSubscribed =false;StartCoroutine(delayDisconnect(4f));}IEnumeratordelayDisconnect(float delay){yieldreturnnewWaitForSeconds(delay);if(bConnected){
      BluetoothLEHardwareInterface.DisconnectPeripheral(device,(address)=>{
        BluetoothLEHardwareInterface.DeInitialize(()=>{
          bConnected =false;});});}else{
      BluetoothLEHardwareInterface.DeInitialize(()=>{});}}publicvoidSubscribeAuth(){
    txtMiBandStatus.text ="Subscribe Characteristic[CHAR_UUIDS.auth]";
    BluetoothLEHardwareInterface.SubscribeCharacteristic(device, UUIDS.miband2, CHAR_UUIDS.auth,null,(characteristicUUID, bytes)=>{string msg ="Received Serial[CHAR_UUIDS.auth]";if(bytes.Length >=3){byte[] code ={ bytes[0], bytes[1], bytes[2]};if(IsEqual(code, AUTH_TYPES.received)){
          msg ="Authenticate Received";}elseif(bytes.Length ==19&&IsEqual(code, AUTH_TYPES.requestcode)){
          msg ="Authenticate Request Code";
          List<byte> serial =newList<byte>();
          serial.AddRange(bytes);
          serial.RemoveRange(0,3);if(serial.Count !=16){
            txtMiBandStatus.text ="Unknown Request Code["+ Utility.Bytes2Hex(serial.ToArray())+"]";
            msg ="";}else{try{byte[] key = Utility.Hex2Bytes(AuthKey);if(key.Length !=16){
                txtMiBandStatus.text ="AuthKey must be 16 bytes["+ AuthKey +"]";
                msg ="";}else{byte[] iv =newbyte[16];byte[] aes =AesEncrypt(serial.ToArray(), key, iv);
                List<byte> ls =newList<byte>();
                ls.Add(0x03);
                ls.Add(0x00);
                ls.AddRange(aes);byte[] authKey = ls.ToArray();
                txtMiBandStatus.text ="Writing Auth Code["+ Utility.Bytes2Hex(authKey)+"]";
                msg ="";
                BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.miband2, CHAR_UUIDS.auth, authKey, authKey.Length,false,(charUUID)=>{
                  txtMiBandStatus.text ="Writed Auth Code["+ Utility.Bytes2Hex(authKey)+"]";});}}catch(System.Exception E){
              msg ="Unknown Exception["+ E.Message +"]";}}}elseif(IsEqual(code, AUTH_TYPES.authfail)){
          msg ="Authenticate Failed";Invoke("SendAuth",5);// retry after 5 seconds}elseif(IsEqual(code, AUTH_TYPES.authed)){
          msg ="Authenticate Successful";

          bAuthed =true;StartCoroutine(delaySubscribeHeartrate(0.5f));}else{
          msg ="Authenticate Received Unknown Message";}}if(!string.IsNullOrEmpty(msg)){
        txtMiBandStatus.text = msg +"["+ bytes.Length.ToString()+"]"+ Utility.Bytes2Hex(bytes);}});}publicvoidSendAuth(){
    txtMiBandStatus.text ="Sending Auth Request["+ Utility.Bytes2Hex(NOTIFICATION_TYPES.auth)+"]";if(bConnected){if(!bAuthed){
        BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.miband2, CHAR_UUIDS.auth, NOTIFICATION_TYPES.auth, NOTIFICATION_TYPES.auth.Length,false,(charUUID)=>{
          txtMiBandStatus.text ="Sent Auth Request["+ Utility.Bytes2Hex(NOTIFICATION_TYPES.auth)+"]["+ charUUID +"]";});}}}publicvoidUnsubscribe(){
    txtMiBandStatus.text ="Unsubscribe";StartCoroutine(delayUnsubscribeHeartrate(1.0f));}stringFullUUID(string uuid){return"0000"+ uuid +"-0000-1000-8000-00805F9B34FB";}boolIsEqual(string uuid1,string uuid2){if(uuid1.Length ==4)
      uuid1 =FullUUID(uuid1);if(uuid2.Length ==4)
      uuid2 =FullUUID(uuid2);return(uuid1.ToUpper().Equals(uuid2.ToUpper()));}boolIsEqual(byte[] data1,byte[] data2){if(data1.Length != data2.Length){returnfalse;}for(int i =0; i < data1.Length;++i){if(data1[i]!= data2[i]){returnfalse;}}returntrue;}// AES CBCpublicstaticbyte[]AesEncrypt(byte[] byteContnet,byte[] byteKEY,byte[] byteIV){var aes =newSystem.Security.Cryptography.RijndaelManaged();;
    aes.Padding = System.Security.Cryptography.PaddingMode.None;
    aes.Mode = System.Security.Cryptography.CipherMode.CBC;

    aes.Key = byteKEY;
    aes.IV = byteIV;var crypto = aes.CreateEncryptor(byteKEY, byteIV);byte[] decrypted = crypto.TransformFinalBlock(byteContnet,0, byteContnet.Length);
    crypto.Dispose();return decrypted;}publicstaticbyte[]Hex2Bytes(string src){
    System.Collections.Generic.List<byte> ls =newSystem.Collections.Generic.List<byte>();char[] chs = src.ToCharArray();for(int i =0; i < chs.Length; i +=2){byte b = System.Convert.ToByte(newstring(chs, i,2),16);
      ls.Add(b);}return ls.ToArray();}publicstaticstringBytes2Hex(byte[] src){
    System.Collections.Generic.List<char> ls =newSystem.Collections.Generic.List<char>();char[] hexDigits ={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};for(int i =0; i < src.Length; i++){
      ls.Add(hexDigits[src[i]>>4&0x0f]);
      ls.Add(hexDigits[src[i]&0x0f]);}returnnewstring(ls.ToArray());}}

以上代码适用于MiBand 3,4,5,不适用于MiBand 6,Auth验证方法应该有调整了

参考:
Unity3D BLE插件
蓝牙通信插件最新版Bluetooth LE for iOS tvOS and Android.unitypackage

MiBand AuthKey获取
Your Soul, Your Beats! —— 小米手环实时心率采集

GitHub项目
Mi Band 4/5 Heart Rate Monitor

标签: unity c# 游戏引擎

本文转载自: https://blog.csdn.net/qq_31042143/article/details/123469442
版权归原作者 foenix66 所有, 如有侵权,请联系我们删除。

“Unity3D蓝牙连接Mi Band 5手环获取实时心率”的评论:

还没有评论