|
@@ -1,5 +1,6 @@
|
|
|
package com.yanzhenjie.andserver.sample.controller;
|
|
|
|
|
|
+import android.annotation.SuppressLint;
|
|
|
import android.bluetooth.BluetoothAdapter;
|
|
|
import android.bluetooth.le.BluetoothLeScanner;
|
|
|
import android.os.Build;
|
|
@@ -16,10 +17,13 @@ import com.yanzhenjie.andserver.annotation.RestController;
|
|
|
import com.yanzhenjie.andserver.sample.MainActivity;
|
|
|
import com.yanzhenjie.andserver.sample.model.ScannedDevice;
|
|
|
import com.yanzhenjie.andserver.sample.util.Constant;
|
|
|
+import com.yanzhenjie.andserver.sample.util.FileUtils;
|
|
|
import com.yanzhenjie.andserver.sample.util.Result;
|
|
|
+import com.yanzhenjie.andserver.sample.util.UtilsSharedPreference;
|
|
|
import com.yanzhenjie.andserver.util.MediaType;
|
|
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.slf4j.helpers.NOPLogger;
|
|
|
|
|
|
import java.util.Collection;
|
|
|
import java.util.HashMap;
|
|
@@ -28,30 +32,40 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
|
import javax.validation.Valid;
|
|
|
|
|
|
+import cn.jesse.nativelogger.NLogger;
|
|
|
import io.mega.megablelib.MegaAdvParse;
|
|
|
import io.mega.megablelib.MegaBleBuilder;
|
|
|
import io.mega.megablelib.MegaBleCallback;
|
|
|
import io.mega.megablelib.MegaBleClient;
|
|
|
+import io.mega.megablelib.MegaBleConst;
|
|
|
+import io.mega.megablelib.enums.MegaBleBattery;
|
|
|
import io.mega.megablelib.model.MegaBleDevice;
|
|
|
import io.mega.megablelib.model.bean.MegaAdvOnly;
|
|
|
import io.mega.megablelib.model.bean.MegaAdvertisingParsedEntity;
|
|
|
+import io.mega.megablelib.model.bean.MegaBleHeartBeat;
|
|
|
+import io.mega.megablelib.model.bean.MegaV2LiveSpoLive;
|
|
|
+import io.mega.megablelib.model.bean.MegaV2LiveSpoMonitor;
|
|
|
+import io.mega.megablelib.model.bean.MegaV2Mode;
|
|
|
import io.reactivex.Observable;
|
|
|
+import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
|
|
|
|
// Created by Develoven on 2023/4/23.
|
|
|
// Copyright (c) 2023 redflow. All rights reserved.
|
|
|
//
|
|
|
-@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
|
|
|
@RestController
|
|
|
@RequestMapping("/common")
|
|
|
public class CommonController extends BaseController{
|
|
|
|
|
|
private static final String TAG = "CommonController";
|
|
|
- private final Long SCAN_PERIOD = 5L;
|
|
|
+ private final Long SCAN_PERIOD = 10L;
|
|
|
|
|
|
private static BluetoothAdapter mBluetoothAdapter;
|
|
|
private static BluetoothLeScanner mScanner = null;
|
|
|
// private static BluetoothAdapter.LeScanCallback mLeScanCallback ;
|
|
|
- private static HashMap<String,ScannedDevice> scannedDeviceList = new HashMap<>();
|
|
|
+ private static HashMap<String,Object> scannedDeviceList = new HashMap<>();
|
|
|
+
|
|
|
+ private String fileName;
|
|
|
+ MegaBleClient megaBleClient ;
|
|
|
static {
|
|
|
// mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
|
mBluetoothAdapter = MainActivity.mBluetoothAdapter;
|
|
@@ -71,7 +85,7 @@ public class CommonController extends BaseController{
|
|
|
*/
|
|
|
@GetMapping(value = "/open/bluetooth",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
|
|
public Result openBluetooth(){
|
|
|
-
|
|
|
+ Log.d(TAG, fileName == null?"fileName == null":fileName);
|
|
|
//1.open bluetooth
|
|
|
if (mBluetoothAdapter == null) {
|
|
|
Log.e(TAG, "--------------- current device not support bluetooth ");
|
|
@@ -87,6 +101,7 @@ public class CommonController extends BaseController{
|
|
|
Log.e(TAG, "--------------- bluetooth open success");
|
|
|
return fail(null,"bluetooth open success");
|
|
|
}
|
|
|
+
|
|
|
return success(null,"bluetooth open success");
|
|
|
|
|
|
}
|
|
@@ -133,44 +148,73 @@ public class CommonController extends BaseController{
|
|
|
* model = PULSE|ECG
|
|
|
* @return
|
|
|
*/
|
|
|
- @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
|
|
|
+ @SuppressLint("CheckResult")
|
|
|
@GetMapping(value = "/scan/device/{model}",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
|
|
- public Result<Collection<ScannedDevice>> scanDevice(@PathVariable("model") String model) throws InterruptedException {
|
|
|
+ public Result scanDevice(@PathVariable("model") String model) throws InterruptedException {
|
|
|
+ Log.d(TAG, fileName == null?"fileName == null":fileName);
|
|
|
AtomicBoolean scanStatus = new AtomicBoolean(true);
|
|
|
BluetoothAdapter.LeScanCallback mLeScanCallback = (device, rssi, scanRecord) -> {
|
|
|
try{
|
|
|
+
|
|
|
Log.d(TAG+"LeScan","device:{"+device.getName()+" "+rssi+" "+scanRecord);
|
|
|
if(StringUtils.isEmpty(device.getName())) {
|
|
|
return;
|
|
|
}
|
|
|
- if (!device.getName().toLowerCase().contains("ring")) return;
|
|
|
- if(scanRecord.length < 62) return;
|
|
|
- // parse 3rd ring
|
|
|
- MegaAdvOnly advOnly = MegaAdvParse.parse(scanRecord);
|
|
|
- //parse 2nd ring
|
|
|
- if(advOnly == null){
|
|
|
- MegaAdvertisingParsedEntity advEntity = MegaBleClient.parseScanRecord(device, scanRecord);
|
|
|
- if(advEntity != null){
|
|
|
- Log.d(TAG,advEntity.toString());
|
|
|
+ if(model.equals(Constant.MODEL_PULSE)){
|
|
|
+ if (!device.getName().toLowerCase().contains("ring")) return;
|
|
|
+ if(scanRecord.length < 62) return;
|
|
|
+ // parse 3rd ring
|
|
|
+ MegaAdvOnly advOnly = MegaAdvParse.parse(scanRecord);
|
|
|
+ //parse 2nd ring
|
|
|
+ if(advOnly == null){
|
|
|
+ MegaAdvertisingParsedEntity advEntity = MegaBleClient.parseScanRecord(device, scanRecord);
|
|
|
+ if(advEntity != null){
|
|
|
+ Log.d(TAG,advEntity.toString());
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ Log.d(TAG,advOnly.toString());
|
|
|
}
|
|
|
- }else {
|
|
|
- Log.d(TAG,advOnly.toString());
|
|
|
- }
|
|
|
- ScannedDevice scannedDevice = new ScannedDevice(device.getName(), device.getAddress(), rssi);
|
|
|
- Log.d(TAG, "device: "+scannedDevice);
|
|
|
+ ScannedDevice scannedDevice = new ScannedDevice(device.getName(), device.getAddress(), rssi);
|
|
|
+ Log.d(TAG, "device: "+scannedDevice);
|
|
|
/*int index = scannedDeviceList.indexOf(scannedDevice);
|
|
|
if(index == -1){
|
|
|
scannedDeviceList.add(scannedDevice);
|
|
|
}else {
|
|
|
scannedDeviceList.add(index,scannedDevice);
|
|
|
}*/
|
|
|
- scannedDeviceList.put(scannedDevice.getAddress(),scannedDevice);
|
|
|
+ scannedDeviceList.put(scannedDevice.getAddress(),scannedDevice);
|
|
|
+ }else if(model.equals(Constant.MODEL_ECG)){
|
|
|
+ if (!device.getName().toLowerCase().contains("bw-ecg")) return;
|
|
|
+ scannedDeviceList.put(device.getAddress(),device.getAddress());
|
|
|
+ }
|
|
|
+
|
|
|
}catch (Exception e ){
|
|
|
Log.d(TAG,e.getMessage());
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
};
|
|
|
- switch (model){
|
|
|
+ Log.d(TAG,"model="+model);
|
|
|
+ //scan PULSE device
|
|
|
+ Log.d(TAG,"size---"+scannedDeviceList.size());
|
|
|
+ if(scannedDeviceList.size()>0){
|
|
|
+ scannedDeviceList.clear();
|
|
|
+ }
|
|
|
+ Log.d(TAG,"size---"+scannedDeviceList.size());
|
|
|
+ //scan ecg device
|
|
|
+ Observable.timer(SCAN_PERIOD,TimeUnit.SECONDS).subscribe( aLong -> {
|
|
|
+ mBluetoothAdapter.stopLeScan(mLeScanCallback);
|
|
|
+ scanStatus.set(false);
|
|
|
+ Log.d(TAG,"scannedDeviceList.size---"+scannedDeviceList.size());
|
|
|
+ });
|
|
|
+ Log.d(TAG,"mLeScanCallback---"+mLeScanCallback);
|
|
|
+ Log.d(TAG,"mBluetoothAdapter---"+mBluetoothAdapter);
|
|
|
+ Log.i(TAG,"开始扫描");
|
|
|
+ mBluetoothAdapter.startLeScan(mLeScanCallback);
|
|
|
+ Observable.interval(1,TimeUnit.SECONDS).take(SCAN_PERIOD).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong ->{
|
|
|
+ Log.d(TAG,aLong.toString()+"scanning...");
|
|
|
+
|
|
|
+ });
|
|
|
+ /*switch (model){
|
|
|
|
|
|
case Constant.MODEL_ECG:
|
|
|
|
|
@@ -193,16 +237,18 @@ public class CommonController extends BaseController{
|
|
|
Log.d(TAG,"mBluetoothAdapter---"+mBluetoothAdapter);
|
|
|
Log.i(TAG,"开始扫描");
|
|
|
mBluetoothAdapter.startLeScan(mLeScanCallback);
|
|
|
-/* Observable.interval(1,TimeUnit.SECONDS).take(SCAN_PERIOD).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong ->{
|
|
|
+ Observable.interval(1,TimeUnit.SECONDS).take(SCAN_PERIOD).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong ->{
|
|
|
Log.d(TAG,aLong.toString()+"scanning...");
|
|
|
|
|
|
- });*/
|
|
|
+ });
|
|
|
break;
|
|
|
- }
|
|
|
+ }*/
|
|
|
while (scanStatus.get()){
|
|
|
Thread.sleep(1000);
|
|
|
+ Log.d(TAG, scanStatus+"---"+System.currentTimeMillis()+"----");
|
|
|
Log.i(TAG,"等待");
|
|
|
}
|
|
|
+
|
|
|
return success(scannedDeviceList.values());
|
|
|
}
|
|
|
|
|
@@ -210,29 +256,152 @@ public class CommonController extends BaseController{
|
|
|
* connect bluetooth
|
|
|
* @return
|
|
|
*/
|
|
|
- @PostMapping(value = "/connect/bluetooth",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
|
|
+ @PostMapping(value = "/connect/bluetooth/{model}",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
|
|
public Result connectBluetooth(@Valid @RequestParam(name = "mac") String mac,@Valid @RequestParam(name = "name") String name){
|
|
|
Log.i(TAG,mac);
|
|
|
+ fileName = "测试文件名称";
|
|
|
MegaBleCallback megaBleCallback = new MegaBleCallback() {
|
|
|
@Override
|
|
|
public void onConnectionStateChange(boolean connected, MegaBleDevice device) {
|
|
|
super.onConnectionStateChange(connected, device);
|
|
|
//状态变更 :通知前台服务
|
|
|
if(connected){
|
|
|
+ Log.d(TAG, "已连接:"+device);
|
|
|
+ }else {
|
|
|
+ Log.d(TAG, "断开连接");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void onError(int code) {
|
|
|
+ NLogger.e(TAG,"error code :{}",code);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onStart() {
|
|
|
+ String userId = "5837288dc59e0d00577c5f9a";
|
|
|
+ String token = UtilsSharedPreference.get(MainActivity.context,UtilsSharedPreference.KEY_TOKEN);
|
|
|
+ if(StringUtils.isEmpty(token)){
|
|
|
+ megaBleClient.startWithToken(userId, "0,0,0,0,0,0");
|
|
|
+ }else {
|
|
|
+ megaBleClient.startWithToken(userId, token);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onDeviceInfoReceived(MegaBleDevice device) {
|
|
|
+ megaBleClient.getV2Batt();
|
|
|
+ megaBleClient.getV2Mode();
|
|
|
+ megaBleClient.enableV2ModeSpoMonitor(true);
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void onSetUserInfo() {
|
|
|
+ megaBleClient.setUserInfo((byte) 25, (byte) 1, (byte) 170, (byte) 60, (byte) 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onIdle() {
|
|
|
+ // 设备闲时,可开启实时、开启长时监控、收监控数据。
|
|
|
+ // 长时监控数据会被记录到戒指内部,实时数据不会。
|
|
|
+ // 长时监控开启后,可断开蓝牙连接,戒指将自动保存心率血氧数据,以便后续手机连上收取。默认每次连上会同步过来。
|
|
|
+ // 绑定token有变动时,用户信息,监测数据将被清空。
|
|
|
+ // 建议默认开启全局实时通道,无需关闭,重复开启无影响
|
|
|
+ // suggested setting, repeated call is ok.
|
|
|
+ Log.d(TAG, "Important: the remote device is idle.");
|
|
|
+ megaBleClient.toggleLive(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onV2LiveSpoLive(MegaV2LiveSpoLive live) {
|
|
|
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onV2LiveSpoMonitor(MegaV2LiveSpoMonitor live) {
|
|
|
+ /* switch (live.getStatus()){
|
|
|
+ case MegaBleConst.STATUS_LIVE_VALID:
|
|
|
+ updateV2Live(live);
|
|
|
+ break;
|
|
|
+ case MegaBleConst.STATUS_LIVE_PREPARING
|
|
|
+ updateV2Live(live);
|
|
|
+ break;
|
|
|
+ case MegaBleConst.STATUS_LIVE_INVALID
|
|
|
+ updateV2Live(live);
|
|
|
+ break;
|
|
|
+
|
|
|
+ }*/
|
|
|
+ }
|
|
|
+
|
|
|
+ //notice user to shaking ,in order to bind the ring
|
|
|
+ @Override
|
|
|
+ public void onKnockDevice() {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onTokenReceived(String token) {
|
|
|
+ UtilsSharedPreference.put(MainActivity.context, UtilsSharedPreference.KEY_TOKEN, token);
|
|
|
+ }
|
|
|
+
|
|
|
+ //notice UI modify rssi
|
|
|
+ @Override
|
|
|
+ public void onRssiReceived(int rssi) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * notify front to change battery value & battery status
|
|
|
+ *
|
|
|
+ * @param value 电池电量
|
|
|
+ * @param status 电池状态 normal(0, "normal"), charging(1, "charging"),full(2, "full"),lowPower(3, "lowPower");error(4, "error");shutdown(5, "shutdown");
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void onBatteryChanged(int value, int status) {
|
|
|
+// MegaBleBattery.getDescription(status);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * notify front active mode
|
|
|
+ * @param mode
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void onV2ModeReceived(MegaV2Mode mode) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 心跳检测,检测到心跳就开启脉搏
|
|
|
+ * @param heartBeat
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void onHeartBeatReceived(MegaBleHeartBeat heartBeat) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onRawdataParsed(int[][] a) {
|
|
|
+ if(a != null && a.length > 0){
|
|
|
+ for (int[] ints : a) {
|
|
|
+ FileUtils.addFile(MainActivity.context.getFilesDir().getPath() + "/脉诊'", String.valueOf(ints[0]));
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
// mock id, key,use yours
|
|
|
MegaBleBuilder builder = new MegaBleBuilder();
|
|
|
- MegaBleClient megaBleClient = builder
|
|
|
- .withSecretId("D4CE5DD515F81247")
|
|
|
- .withSecretKey("uedQ2MgVEFlsGIWSgofHYHNdZSyHmmJ5")
|
|
|
- .withCallback(megaBleCallback)
|
|
|
- .build();
|
|
|
+ try{
|
|
|
+ megaBleClient = builder
|
|
|
+ .withSecretId("D4CE5DD515F81247")
|
|
|
+ .withSecretKey("uedQ2MgVEFlsGIWSgofHYHNdZSyHmmJ5")
|
|
|
+ .withContext(MainActivity.context)
|
|
|
+ .withCallback(megaBleCallback)
|
|
|
+ .build();
|
|
|
+ }catch (Exception e ){
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
// 开发测试时,可以开启debug
|
|
|
megaBleClient.setDebugEnable(true);
|
|
|
megaBleClient.connect(mac, name);
|
|
|
+
|
|
|
return success();
|
|
|
}
|
|
|
|