0


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

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

  1. 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
  2. {
  3. None,
  4. Scan,
  5. Connect,
  6. Auth,
  7. Subscribe,
  8. Unsubscribe,
  9. Disconnect,
  10. 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(){
  11. bConnected =false;
  12. bAuthed =false;
  13. device =null;
  14. foundChartAuth =false;
  15. foundChartHeartrateControl =false;
  16. foundChartHeartrateMeasurement =false;
  17. foundChartSensor =false;
  18. PanelMiddle.SetActive(false);}voidInitBLE(){
  19. txtMiBandStatus.text ="";
  20. txtBluetoothStatus.text ="Initializing...";Reset();
  21. BluetoothLEHardwareInterface.Initialize(true,false,()=>{StartCoroutine(delayScan(0.1f));
  22. txtBluetoothStatus.text ="Initialized";},(error)=>{
  23. BluetoothLEHardwareInterface.Log("Error: "+ error);});}// Use this for initializationvoidStart(){InitBLE();}// Update is called once per framevoidUpdate(){}IEnumeratordelayScan(float delay){yieldreturnnewWaitForSeconds(delay);
  24. txtBluetoothStatus.text ="Scanning devices["+ DeviceName +"]";
  25. 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)){
  26. DeviceName = name;// it is always a good idea to stop scanning while you connect to a device// and get things set up
  27. BluetoothLEHardwareInterface.StopScan();
  28. txtBluetoothStatus.text ="";// add it to the list and set to connect to it
  29. device = address;
  30. txtMiBandLabel.text = DeviceName +"["+ device +"]";
  31. txtMiBandStatus.text ="Found "+ DeviceName;StartCoroutine(delayConnect(0.5f));}},null,false,false);}IEnumeratordelayConnect(float delay){yieldreturnnewWaitForSeconds(delay);// set these flags
  32. 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.
  33. BluetoothLEHardwareInterface.ConnectToPeripheral(device,null,null,(address, serviceUUID, characteristicUUID)=>{if(IsEqual(serviceUUID, UUIDS.miband2)&&IsEqual(characteristicUUID, CHAR_UUIDS.auth)){
  34. foundChartAuth =true;}elseif(IsEqual(serviceUUID, UUIDS.heartrate)&&IsEqual(characteristicUUID, CHAR_UUIDS.heartrate_control)){
  35. foundChartHeartrateControl =true;}elseif(IsEqual(serviceUUID, UUIDS.heartrate)&&IsEqual(characteristicUUID, CHAR_UUIDS.heartrate_measure)){
  36. foundChartHeartrateMeasurement =true;}elseif(IsEqual(serviceUUID, UUIDS.miband1)&&IsEqual(characteristicUUID, CHAR_UUIDS.sensor)){
  37. foundChartSensor =true;}// all need characteristics foundif(foundChartAuth && foundChartHeartrateControl && foundChartHeartrateMeasurement && foundChartSensor){
  38. bConnected =true;
  39. 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)=>{
  40. BluetoothLEHardwareInterface.Log("Device disconnected: "+ disconnectedAddress);
  41. txtMiBandStatus.text ="Disconnected";
  42. bConnected =false;
  43. bAuthed =false;
  44. bSubscribed =false;});}IEnumeratordelayAuthenticate(float delay){
  45. PanelMiddle.SetActive(true);yieldreturnnewWaitForSeconds(delay);SubscribeAuth();yieldreturnnewWaitForSeconds(0.5f);SendAuth();}IEnumeratordelaySubscribeHeartrate(float delay){yieldreturnnewWaitForSeconds(delay);
  46. BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_control,
  47. HEARTRATECONTROL_TYPES.stop_heartrate_auto, HEARTRATECONTROL_TYPES.stop_heartrate_auto.Length,false,(charUUID)=>{});yieldreturnnewWaitForSeconds(0.5f);
  48. BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_control,
  49. HEARTRATECONTROL_TYPES.stop_heartrate_manual, HEARTRATECONTROL_TYPES.stop_heartrate_manual.Length,false,(charUUID)=>{});yieldreturnnewWaitForSeconds(0.5f);
  50. BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_measure,null,(address, characteristicUUID, bytes)=>{
  51. txtMiBandStatus.text ="Received Subscribe["+ bytes.Length.ToString()+"]["+ Time.time.ToString("F2")+"]"+ Utility.Bytes2Hex(bytes)+"";if(2== bytes.Length){byte[] heartrate ={ bytes[1], bytes[0]};
  52. txtHeartRate.text = System.BitConverter.ToInt16(heartrate,0).ToString("D3")+"BPM";}elseif(1== bytes.Length){
  53. txtHeartRate.text =((int)(bytes[0])).ToString("D3")+"BPM";}});yieldreturnnewWaitForSeconds(0.5f);
  54. txtMiBandStatus.text ="Starting manual heart rate detection...";
  55. BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_control,
  56. HEARTRATECONTROL_TYPES.start_heartrate_manual, HEARTRATECONTROL_TYPES.start_heartrate_manual.Length,false,(charUUID)=>{
  57. txtMiBandStatus.text ="Startedmanual heart rate detection...";});while(bSubscribed){yieldreturnnewWaitForSeconds(12f);
  58. BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_control,
  59. HEARTRATECONTROL_TYPES.ping, HEARTRATECONTROL_TYPES.ping.Length,false,(charUUID)=>{});}}IEnumeratordelayUnsubscribeHeartrate(float delay){yieldreturnnewWaitForSeconds(delay);
  60. BluetoothLEHardwareInterface.UnSubscribeCharacteristic(device, UUIDS.heartrate, CHAR_UUIDS.heartrate_measure,null);
  61. bSubscribed =false;StartCoroutine(delayDisconnect(4f));}IEnumeratordelayDisconnect(float delay){yieldreturnnewWaitForSeconds(delay);if(bConnected){
  62. BluetoothLEHardwareInterface.DisconnectPeripheral(device,(address)=>{
  63. BluetoothLEHardwareInterface.DeInitialize(()=>{
  64. bConnected =false;});});}else{
  65. BluetoothLEHardwareInterface.DeInitialize(()=>{});}}publicvoidSubscribeAuth(){
  66. txtMiBandStatus.text ="Subscribe Characteristic[CHAR_UUIDS.auth]";
  67. 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)){
  68. msg ="Authenticate Received";}elseif(bytes.Length ==19&&IsEqual(code, AUTH_TYPES.requestcode)){
  69. msg ="Authenticate Request Code";
  70. List<byte> serial =newList<byte>();
  71. serial.AddRange(bytes);
  72. serial.RemoveRange(0,3);if(serial.Count !=16){
  73. txtMiBandStatus.text ="Unknown Request Code["+ Utility.Bytes2Hex(serial.ToArray())+"]";
  74. msg ="";}else{try{byte[] key = Utility.Hex2Bytes(AuthKey);if(key.Length !=16){
  75. txtMiBandStatus.text ="AuthKey must be 16 bytes["+ AuthKey +"]";
  76. msg ="";}else{byte[] iv =newbyte[16];byte[] aes =AesEncrypt(serial.ToArray(), key, iv);
  77. List<byte> ls =newList<byte>();
  78. ls.Add(0x03);
  79. ls.Add(0x00);
  80. ls.AddRange(aes);byte[] authKey = ls.ToArray();
  81. txtMiBandStatus.text ="Writing Auth Code["+ Utility.Bytes2Hex(authKey)+"]";
  82. msg ="";
  83. BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.miband2, CHAR_UUIDS.auth, authKey, authKey.Length,false,(charUUID)=>{
  84. txtMiBandStatus.text ="Writed Auth Code["+ Utility.Bytes2Hex(authKey)+"]";});}}catch(System.Exception E){
  85. msg ="Unknown Exception["+ E.Message +"]";}}}elseif(IsEqual(code, AUTH_TYPES.authfail)){
  86. msg ="Authenticate Failed";Invoke("SendAuth",5);// retry after 5 seconds}elseif(IsEqual(code, AUTH_TYPES.authed)){
  87. msg ="Authenticate Successful";
  88. bAuthed =true;StartCoroutine(delaySubscribeHeartrate(0.5f));}else{
  89. msg ="Authenticate Received Unknown Message";}}if(!string.IsNullOrEmpty(msg)){
  90. txtMiBandStatus.text = msg +"["+ bytes.Length.ToString()+"]"+ Utility.Bytes2Hex(bytes);}});}publicvoidSendAuth(){
  91. txtMiBandStatus.text ="Sending Auth Request["+ Utility.Bytes2Hex(NOTIFICATION_TYPES.auth)+"]";if(bConnected){if(!bAuthed){
  92. BluetoothLEHardwareInterface.WriteCharacteristic(device, UUIDS.miband2, CHAR_UUIDS.auth, NOTIFICATION_TYPES.auth, NOTIFICATION_TYPES.auth.Length,false,(charUUID)=>{
  93. txtMiBandStatus.text ="Sent Auth Request["+ Utility.Bytes2Hex(NOTIFICATION_TYPES.auth)+"]["+ charUUID +"]";});}}}publicvoidUnsubscribe(){
  94. 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)
  95. uuid1 =FullUUID(uuid1);if(uuid2.Length ==4)
  96. 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();;
  97. aes.Padding = System.Security.Cryptography.PaddingMode.None;
  98. aes.Mode = System.Security.Cryptography.CipherMode.CBC;
  99. aes.Key = byteKEY;
  100. aes.IV = byteIV;var crypto = aes.CreateEncryptor(byteKEY, byteIV);byte[] decrypted = crypto.TransformFinalBlock(byteContnet,0, byteContnet.Length);
  101. crypto.Dispose();return decrypted;}publicstaticbyte[]Hex2Bytes(string src){
  102. 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);
  103. ls.Add(b);}return ls.ToArray();}publicstaticstringBytes2Hex(byte[] src){
  104. 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++){
  105. ls.Add(hexDigits[src[i]>>4&0x0f]);
  106. 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手环获取实时心率”的评论:

还没有评论