elink_health_ring 1.1.0 copy "elink_health_ring: ^1.1.0" to clipboard
elink_health_ring: ^1.1.0 copied to clipboard

Flutter project for Elink Health Ring SDK.

elink_health_ring #

##中文

Elink Health Ring Flutter library.

Prerequisites #

  1. Have obtained the Elink Bluetooth communication protocol
  2. Have a smart device that supports the Elink Bluetooth module
  3. Have Flutter development and debugging knowledge

Android #

  1. Add in android/build.gradle filemaven { url 'https://jitpack.io' }
    allprojects {
        repositories {
            google()
            mavenCentral()
            //add
            maven { url 'https://jitpack.io' }
        }
    }
  1. Set in android/app/build.gradle fileminSdkVersion 21
    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.elinkthings.elink_health_ring_example"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
        minSdkVersion 21 //flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
  1. To use the flutter_blue_plus library, you need to add relevant permissions in the android/app/src/main/AndroidManifest.xml file
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- Tell Google Play Store that your app uses Bluetooth LE
             Set android:required="true" if bluetooth is necessary -->
        <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />

        <!-- New Bluetooth permissions in Android 12
        https://developer.android.com/about/versions/12/features/bluetooth-permissions -->
        <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
        <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

        <!-- legacy for Android 11 or lower -->
        <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>
    
        <!-- legacy for Android 9 or lower -->
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">

iOS #

  1. To use the flutter_blue_plus library, you need to add relevant permissions in the ios/Runner/Info.plist file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>NSBluetoothAlwaysUsageDescription</key>
        <string>This app always needs Bluetooth to function</string>
        <key>NSBluetoothPeripheralUsageDescription</key>
        <string>This app needs Bluetooth Peripheral to function</string>
        <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
        <string>This app always needs location and when in use to function</string>
        <key>NSLocationAlwaysUsageDescription</key>
        <string>This app always needs location to function</string>
        <key>NSLocationWhenInUseUsageDescription</key>
        <string>This app needs location when in use to function</string>
    </dict>
</plist>

Flutter #

Health Ring Instructions #

General instructions

  import 'package:elink_health_ring/utils/elink_health_ring_cmd_utils.dart';
  import 'package:ailink/utils/ble_common_util.dart';
  
  final elinkHealthRingCmdUtils = ElinkHealthRingCmdUtils(bleData.macArr, cid: bleData.cidArr); //macArr and cidArr are obtained from the broadcast
  BluetoothCharacteristic? _dataA7Characteristic; //Get after connecting the device ElinkBleCommonUtils.elinkWriteAndNotifyUuid
  BluetoothCharacteristic? _dataA6Characteristic; //Get after connecting the device ElinkBleCommonUtils.elinkWriteUuid

  Future<void> _sendA6Data(List<int> data) async {
    _dataA6Characteristic?.write(data, withoutResponse: true);
  }
    
  Future<void> _sendA7Data(List<int> data) async {
    _dataA7Characteristic?.write(data, withoutResponse: true);
  }
  
  //Each time you receive an A7 data command, you need to reply to the command to the device, otherwise the device cannot be used normally.
  final data = elinkHealthRingCmdUtils.replyDevice();
  _sendA7Data(data);
  
  //Get sensor version
  final data = elinkHealthRingCmdUtils.getJFSensorInfo();
  _sendA7Data(data);
  
  //Get device state
  final data = elinkHealthRingCmdUtils.getDeviceState();
  _sendA7Data(data);

  //Sync Unix time
  final data = elinkHealthRingCmdUtils.syncUnixTime(syncTime!);
  _sendA6Data(data);
  
  //Sync BLE time
  final data = elinkHealthRingCmdUtils.syncBleTime(syncTime!);
  _sendA6Data(data);
  • ⚠️ WARNING: The syncTime parameter of elinkHealthRingCmdUtils.syncUnixTime(syncTime) and elinkHealthRingCmdUtils.syncBleTime(syncTime) must use the same value

Physical examination and automatic monitoring instructions

  //Get automatic monitoring status
  final data = elinkHealthRingCmdUtils.getAutoCheckState();
  _sendA7Data(data);

  //Enable automatic monitoring
  final data = elinkHealthRingCmdUtils.openAutoCheck();
  _sendA7Data(data);
  
  //Turn off automatic monitoring
  final data = elinkHealthRingCmdUtils.closeAutoCheck();
  _sendA7Data(data);

  //Get automatic monitoring time
  final data = elinkHealthRingCmdUtils.getCheckupDuration();
  _sendA7Data(data);

  //Set the automatic monitoring time
  final duration = 30;//Unit: Minutes
  final data = elinkHealthRingCmdUtils.setCheckupDuration(duration);
  _sendA7Data(data);
  
  //Query automatic monitoring type
  final data = elinkHealthRingCmdUtils.getCheckupType();
  _sendA7Data(data);

  //Set the automatic monitoring type
  final checkupType = index == 0 ? ElinkCheckupType.fast : ElinkCheckupType.complex;
  final data = elinkHealthRingCmdUtils.setCheckupType(checkupType);
  _sendA7Data(data);

  //Start the physical examination
  final data = elinkHealthRingCmdUtils.startCheckup();
  _sendA7Data(data);

  //End of physical examination
  final data = elinkHealthRingCmdUtils.stopCheckup();
  _sendA7Data(data);

  //Obtaining automatic monitoring historical data
  final data = elinkHealthRingCmdUtils.getCheckupHistory();
  _sendA7Data(data);

  //Get the next piece of automatic monitoring history data
  final data = elinkHealthRingCmdUtils.getNextCheckupHistory();
  _sendA7Data(data);
  
  //Get the automatic monitoring history data end
  final data = elinkHealthRingCmdUtils.getCheckupHistoryOver();
  _sendA7Data(data);
  
  //Delete automatic monitoring history data
  final data = elinkHealthRingCmdUtils.deleteCheckupHistory();
  _sendA7Data(data);

Sleep and step count instructions

  //Get sleep and step monitoring time
  final data = elinkHealthRingCmdUtils.getSleepAndStepDuration();
  _sendA7Data(data);

  //Get sleep and step monitoring time
  final duration = 5; //单位分钟
  final data = elinkHealthRingCmdUtils.setSleepAndStepDuration(duration);
  _sendA7Data(data);

  //Get sleep detection status
  final data = elinkHealthRingCmdUtils.getSleepCheckState();
  _sendA7Data(data);
  
  //Turn on sleep detection
  final data = elinkHealthRingCmdUtils.openSleepCheck();
  _sendA7Data(data);
  
  //Turn off sleep detection
  final data = elinkHealthRingCmdUtils.closeSleepCheck();
  _sendA7Data(data);
  
  //Get the step detection status
  final data = elinkHealthRingCmdUtils.getStepCheckState();
  _sendA7Data(data);
  
  //Turn on step detection
  final data = elinkHealthRingCmdUtils.openStepCheck();
  _sendA7Data(data);
  
  //Turn off step detection
  final data = elinkHealthRingCmdUtils.closeStepCheck();
  _sendA7Data(data);

  //Get sleep and step history data
  final data = elinkHealthRingCmdUtils.getSleepAndStepHistory();
  _sendA7Data(data);
  
  //Get the next page of sleep and step history data
  final data = elinkHealthRingCmdUtils.getNextSleepAndStepHistory();
  _sendA7Data(data);
  
  //Get sleep and step history data ended
  final data = elinkHealthRingCmdUtils.getSleepAndStepHistoryOver();
  _sendA7Data(data);

  //Delete sleep and step history data
  final data = elinkHealthRingCmdUtils.deleteSleepAndStepHistory();
  _sendA7Data(data);

Sensor OTA Commands

  import 'package:elink_health_ring/utils/jf_ota_utils.dart';
  JFOTAUtils jfotaUtils = JFOTAUtils(bleData.macArr, cid: bleData.cidArr); //macArr and cidArr are obtained from the broadcast

  //Set OTA file data and start OTA
  final Uint8List fileData; 
  _jfotaUtils.setFileData(fileData);
  final startOta = _jfotaUtils.startOTA();
  _sendA7Data(startOta);
  
  //Wipe Data
  final data = _jfotaUtils.eraseAll(size);
  _sendA7Data(data);
  
  //Writing Data
  final result = _jfotaUtils.pageWrite(data, address);
  _sendA7Data(result);

  //Verify data and
  final data = _jfotaUtils.pageReadChecksum(sum, address);
  _sendA7Data(data);
  
  //End OTA
  final data = _jfotaUtils.endOTA();
  _sendA7Data(data);
  • ⚠️ WARNING: Do not interrupt the operation during the sensor OTA process, as it may cause the device to become unusable.

BLE OTA

  import 'package:elink_health_ring/utils/ota/dialog_ota_listener.dart';
  import 'package:elink_health_ring/utils/ota/dialog_ota_manager.dart';
  
  final DialogOtaManager _dialogOtaManager = DialogOtaManager();

  //1. After the device is successfully connected and the service is discovered, call _dialogOtaManager.setServices(services);
  _bluetoothDevice?.discoverServices().then((services) {
    _dialogOtaManager.setServices(services);
  }, onError: (error) {
  });
  
  //2. Set OTA file data and start OTA
  final Uint8List fileData;
  _dialogOtaManager.setDataAndStart(fileData, listener: this);

  abstract class DialogOtaListener {
    void onOtaSuccess();  //OTA upgrade completed
    
    void onOtaFailure(int code, String msg);  //OTA upgrade failed code: error code msg: error message
    
    void onOtaProgress(double progress);  //OTA upgrade progress 0-100
  }
  • ⚠️ WARNING: After the Bluetooth OTA is successful, the device will restart. If you do not receive the device's broadcast, please use the charger to activate the device.

Health Ring Reporting Instructions #

General command callback

  import 'package:elink_health_ring/utils/elink_health_ring_data_parse_utils.dart';
  import 'package:elink_health_ring/utils/elink_health_ring_common_callback.dart';
  
  ElinkHealthRingDataParseUtils elinkHealthRingDataParseUtils = ElinkHealthRingDataParseUtils(bleData.macArr, cid: bleData.cidArr);
  elinkHealthRingDataParseUtils.setCallback(
    commonCallback: ElinkHealthRingCommonCallback(
      onDeviceStatusChanged: (status) { //Device State ElinkHealthRingStatus
      },
      onGetSensorVersion: (version) { //Sensor version
      },
      onSetUnixTimeResult: (result) { //Set the Unix time result, true: success, false: failure
      },
      onSyncBleTimeResult: (result) { //Set the BLE time result, true: success, false: failure
      }
    ),
  );

Automatic monitoring and physical examination instruction callback

  elinkHealthRingDataParseUtils.setCallback(
    checkupCallback: ElinkHealthRingCheckupCallback(
      onStartCheckup: (success) { //Start physical examination, true: success, false: failure
      },
      onStopCheckup: (success) { //End physical examination, true: success, false: failure
      },
      onGetRealtimeData: (data) { //Real-time physical examination data ElinkCheckupRealtimeData
      },
      onGetCheckupPackets: (data) { //Physical examination package List<int> 
      },
      onGetCheckupDuration: (duration) { //Automatic monitoring cycle, unit: minutes
      },
      onGetCheckupHistory: (list, total, sentCount) { //Automatic monitoring history, list: List<ElinkCheckupHistoryData>, total: total number of records, sentCount: number of sent records
      },
      onGetAutoCheckupStatus: (open) { //Automatically monitor the switch status, true: on, false: off
      },
      onGetCheckupType: (type) { //Automatic monitoring type,ElinkCheckupType
      },
      onNotifyCheckupHistoryGenerated: () { //Automatic monitoring record generation notification
      },
    ),
  );

Sleep and step count command callbacks

  elinkHealthRingDataParseUtils.setCallback(
    sleepStepCallback: ElinkHealthRingSleepStepCallback(
      onGetCheckDuration: (duration) { //Sleep and step monitoring cycle, in minutes
      },
      onGetSleepAndStepHistory: (list, total, sentCount) {  //Sleep and step history, list: List<ElinkSleepAndStepData>, total: total number of records, sentCount: number of records sent
      },
      onNotifySleepAndStepHistoryGenerated: () {  //Sleep and step count log generation notifications
      },
      onGetSleepCheckState: (open) {  //Sleep monitoring status, true: on, false: off
      },
      onGetStepCheckState: (open) {  //Step monitoring status, true: on, false: off
      },
    ),
  );

Sensor OTA callback

    final _jfotaUtils = JFOTAUtils(bleData.macArr, cid: bleData.cidArr);
    elinkHealthRingDataParseUtils.setCallback(jfotaUtils: _jfotaUtils) //Set JFOTAUtils to process the chip OTA instructions reported by the device

    _jfotaUtils.setListener(
      onStartSuccess: (size) async { //Start chip OTA successfully, clear data automatically
        final data = _jfotaUtils.eraseAll(size);
        _sendA7Data(data);
      },
      onOtaPageWrite: (data, address) async { //Actively write data
        final result = _jfotaUtils.pageWrite(data, address);
        _sendA7Data(result);
      },
      onOtaPageReadChecksum: (sum, address) async { //Verify data and
        final data = _jfotaUtils.pageReadChecksum(sum, address);
        _sendA7Data(data);
      },
      onFailure: (type) async { //OTA failed, automatically terminate OTA
        final data = _jfotaUtils.endOTA();
        _sendA7Data(data);
      },
      onSuccess: () async { //OTA is successful, automatically end OTA
        final data = _jfotaUtils.endOTA();
        _sendA7Data(data);
      },
      onProgressChanged: (progress) { //OTA progress callback
      },
    );

Common Class Description #

ElinkCheckupHistoryData

  ElinkCheckupHistoryData(
    this.heartRate, //Heart rate
    this.spo, //Blood oxygen
    this.bk,  //Microcirculation
    this.sbp, //Systolic blood pressure (high pressure)
    this.dbp, //Diastolic blood pressure (low pressure)
    this.rr,  //Respiratory rate
    this.sdann,
    this.rmssd,
    this.nn50,
    this.pnn50,
    this.time,  //时间(毫秒)
    this.rri,
  );

ElinkCheckupRealtimeData

  ElinkCheckupRealtimeData(
    this.heartRate, //Heart rate
    this.bloodOxygen, //Blood oxygen
    this.heartList, //Heart rhythm
    this.rr,
    this.rri,
  );

ElinkHealthRingStatus

  ElinkHealthRingStatus(
    this.state, //Historical data status
    this.batteryLevel,  //Battery level
    this.isCharging,  //Whether charging
    this.wearingStatus, //Wearing status
  );

ElinkSleepAndStepData

  ElinkSleepAndStepData(
    this.time,  //Time (milliseconds)
    this.sleepState,  //Sleep state
    this.steps  //Number of steps
  );

ElinkCheckupType

  enum ElinkCheckupType { 
    fast, //Quick physical examination (excluding emotional value)
    complex, //Full physical examination
  }

ElinkHealthRingHistoryState

  enum ElinkHealthRingHistoryState {
    notReady, //Historical time is not ready (Unix time not obtained)
    processing, //Historical time is being processed (Unix time obtained, historical data being processed)
    ready, //Historical time is ready (only in this state can the device history be obtained)
  }

ElinkWearingStatus

  enum ElinkWearingStatus {
    unsupported, //Not supported
    notWearing, //Not wearing
    wearing, //Wearing
  }

  enum ElinkSleepState {
    awake, //awake
    rem, //rapid eye movement
    light, //light sleep
    deep, //deep sleep
  }

For specific usage, please refer to the example