iHealth Device Integration Android


1. Introduction

Before working with iHealth devices SDK you need to learn android multithreading communication pattern with Handlers and Messages. You’ve to have complete understanding of those two classes and how they are used to communicate and pass data between two threads.

2. The way it works

You need to register a callback (iHealthDevicesCallback) to receive connection state and perform operations on it. This callback will be triggered with startDiscovery() method within iHealthDevices singleton instance. This callback interface has several methods that needs to be overriden.

  • onScanDevice(String mac, String deviceType, int rssi)
  • onScanFinish()
  • onDeviceConnectionStateChange(String mac, String deviceType, int status, int errorID)
If any iHealth device is found onScanDevice() method will be called. To connect to that device send a command to the handler CONNECT_DEVICE

myHandler.sendEmptyMessage(CONNECT_DEVICE);


Those command codes needs to be declared first as constants.

private static final int ADD_SUCCESS = 101;
private static final int ADD_FAIL = 102;
private static final int SCAN_DEVICE = 103;
private static final int CONNECT_DEVICE = 104;
private static final int DISCONNECT_DEVICE = 105;

If a device is connected or disconnected or failed onDeviceConnectionStateChange() method will be called.

Constants to determine the states are:
iHealthDevicesManager.DEVICE_STATE_CONNECTED
iHealthDevicesManager.DEVICE_STATE_CONNECTIONFAIL
iHealthDevicesManager.DEVICE_STATE_DISCONNECTED
And others like them.

Take control over your device if connection is successful.
Like this one:

Bp7Control bp7Control = iHealthDevicesManager.getInstance().getBp7Control(mAddress);

For different devices this control classes will be defferent. But naming conventions are the same.

Okay it was a brief overview. Lets follow some steps so that we can successfully connect our iHealth Device within out app.


Steps

Step1:

Put your binaries(.jar, .so) into /app/libs folder of your project and compile all of the files on build.gradle
(Those sdk binaries can be downloaded from here or this github repo. This link includes binaries needed for integrating mCloud devices too)

compile fileTree(dir: 'libs', include: ['*.jar'])
compile files('libs/d2xx.jar')
compile files('libs/iHealthLibrary_2.3.1.jar')
compile files('libs/pl2303driver.jar')
compile files('libs/smartlinklib3.6.4_product.jar')



Step 2:

Initialize iHealth SDK on your application class

iHealthDevicesManager.getInstance().init(this);

Step 3: Make Connection:

Create a Class named MeasureHelperIHealth that is responsible for connecting to the device.
Register a callback and add device filter (like which type of device you want to connect, bp7 or spo2 etc)

public MeasureHelperIHealth(Context context) {
  this.context = context;

  callbackId = iHealthDevicesManager.getInstance().registerClientCallback(miHealthDevicesCallback);

  iHealthDevicesManager.getInstance().addCallbackFilterForDeviceType(callbackId, iHealthDevicesManager.TYPE_BP7);
  iHealthDevicesManager.getInstance().sdkUserInAuthor(context, userName, clientId,
          clientSecret, callbackId);

  myHandler = new MyHandler();

}

Remember to call sdkUserInAuthor() method to verify your identity. Client ID and Client Secret can be found registering iHealth website and adding new app there.


iHealth Device Callback:

private boolean connectionLock = false;
  private boolean getConnectionLock = false;
  private boolean isDisconnectLock = false;
  private iHealthDevicesCallback miHealthDevicesCallback = new iHealthDevicesCallback() {
      @Override
      public void onScanDevice(String mac, String deviceType, int rssi) {
          if (mStatusView!=null) mStatusView.setText("Scanning for device..");
          Log.i(TAG, "onScanDevice:" + mac + " - " + deviceType);
          mAddress = mac;
          if ((!connectionLock)) {
              getConnectionLock = true;
              connectionLock = true;
              myHandler.sendEmptyMessage(CONNECT_DEVICE);
          }
      }

      @Override
      public void onScanFinish() {
          if (!getConnectionLock) {
              iHealthDevicesManager.getInstance().startDiscovery(iHealthDevicesManager.DISCOVERY_BP7);
          }
      }

      @Override
      public void onDeviceConnectionStateChange(String mac, String deviceType, int status, int errorID) {
          connectionLock = false;
          getConnectionLock = false;
          if (iHealthDevicesManager.DEVICE_STATE_CONNECTED == status) {
              if (mStatusView!=null) mStatusView.setText("Connected!");
              myHandler.sendEmptyMessage(ADD_SUCCESS);
              isDisconnectLock = true;
              SystemClock.sleep(2000);
              ((CoreActivity) context).loadFragment(BPReadingFragment_.builder().mac(mac).build());
//                myHandler.sendEmptyMessage(DISCONNECT_DEVICE);

          } else if (iHealthDevicesManager.DEVICE_STATE_CONNECTIONFAIL == status) {
              if (mStatusView!=null) mStatusView.setText("Connection failed. Remember to swictch on the device and check if your device's Bluetooth is on.");
              myHandler.sendEmptyMessage(ADD_FAIL);
              myHandler.sendEmptyMessage(SCAN_DEVICE);

          } else if (iHealthDevicesManager.DEVICE_STATE_DISCONNECTED == status) {
              if (mStatusView!=null) mStatusView.setText("Disconnected!");
//                SystemClock.sleep(2000);
//                myHandler.sendEmptyMessage(SCAN_DEVICE);
          }
      }

  };

 

We’re using myHandler to send message to the background thread in which we can call connectDevice(), startDiscovery(), disconnect() methods on background.


  • On onDeviceConnectionStateChange() method check if device is connected. If yes then open an activity or fragment of whatever.
  • Perform operation on that fragment/activity like measuring etc.

Step 4:

Trigger Device discovery for the first time so that callback is operational.
iHealthDevicesManager.getInstance().startDiscovery(iHealthDevicesManager.DISCOVERY_BP7);

Measurement:


Step 1:

Create a fragment BpReadingFragment (illustrating example for bp7 device)
Step 2:
On onCreateView() initialize callback, add filter, authorise sdk
clientCallbackId = iHealthDevicesManager.getInstance().registerClientCallback(miHealthDevicesCallback);
      /* Limited wants to receive notification specified device */
      iHealthDevicesManager.getInstance().addCallbackFilterForDeviceType(clientCallbackId, iHealthDevicesManager.TYPE_BP7);
//    /* Get bp7 controller */
      iHealthDevicesManager.getInstance().sdkUserInAuthor(getActivity(), userName, clientId,
              clientSecret, clientCallbackId);
      bp7Control = iHealthDevicesManager.getInstance().getBp7Control(mac);


If you use androidannotations it might be afterViews() method. But whatever!

Step 3:
Callback for reading data:

private iHealthDevicesCallback miHealthDevicesCallback = new iHealthDevicesCallback() {

      @Override
      public void onDeviceConnectionStateChange(String mac,
                                                String deviceType, int status, int errorID) {
          Log.i(TAG, "mac: " + mac);
          Log.i(TAG, "deviceType: " + deviceType);
          Log.i(TAG, "status: " + status);
      }

      @Override
      public void onUserStatus(String username, int userStatus) {
          Log.i(TAG, "username: " + username);
          Log.i(TAG, "userState: " + userStatus);
      }

      @Override
      public void onDeviceNotify(String mac, String deviceType,
                                 String action, String message) {
          Log.i(TAG, "mac: " + mac);
          Log.i(TAG, "deviceType: " + deviceType);
          Log.i(TAG, "action: " + action);
          Log.i(TAG, "message: " + message);

          if (BpProfile.ACTION_BATTERY_BP.equals(action)) {
              try {
                  JSONObject info = new JSONObject(message);
                  String battery = info.getString(BpProfile.BATTERY_BP);
                  Message msg = new Message();
                  msg.what = HANDLER_MESSAGE;
                  Map<String, String> map = new HashMap<>();
                  map.put("battery", battery);
                  msg.obj = map;
//                    msg.obj = "battery: " + battery;
                  myHandler.sendMessage(msg);
              } catch (JSONException e) {
                  e.printStackTrace();
              }


          } else if (BpProfile.ACTION_DISENABLE_OFFLINE_BP.equals(action)) {
              Log.i(TAG, "disable operation is success");

          } else if (BpProfile.ACTION_ENABLE_OFFLINE_BP.equals(action)) {
              Log.i(TAG, "enable operation is success");

          } else if (BpProfile.ACTION_ERROR_BP.equals(action)) {
              try {
                  JSONObject info = new JSONObject(message);
                  String num = info.getString(BpProfile.ERROR_NUM_BP);
                  Message msg = new Message();
                  msg.what = HANDLER_MESSAGE;
                  Map<String, String> map = new HashMap<>();
                  map.put("errorNum", num);
                  msg.obj = map;
//                    msg.obj = "error num: " + num;
                  myHandler.sendMessage(msg);
              } catch (JSONException e) {
                  e.printStackTrace();
              }

          } else if (BpProfile.ACTION_HISTORICAL_DATA_BP.equals(action)) {
              Map<String, String> map = new HashMap<>();
              try {
                  JSONObject info = new JSONObject(message);
                  if (info.has(BpProfile.HISTORICAL_DATA_BP)) {
                      JSONArray array = info.getJSONArray(BpProfile.HISTORICAL_DATA_BP);
                      for (int i = 0; i < array.length(); i++) {
                          JSONObject obj = array.getJSONObject(i);
                          String date = obj.getString(BpProfile.MEASUREMENT_DATE_BP);
                          String hightPressure = obj.getString(BpProfile.HIGH_BLOOD_PRESSURE_BP);
                          String lowPressure = obj.getString(BpProfile.LOW_BLOOD_PRESSURE_BP);
                          String pulseWave = obj.getString(BpProfile.PULSE_BP);
                          String ahr = obj.getString(BpProfile.MEASUREMENT_AHR_BP);
                          String hsd = obj.getString(BpProfile.MEASUREMENT_HSD_BP);
                          map.put("hightPressure", hightPressure);
                          map.put("lowPressure", lowPressure);
                          map.put("pulseWave", pulseWave);
                          map.put("ahr", ahr);
                          map.put("hsd", hsd);
//                            str = "date:" + date
//                                    + "hightPressure:" + hightPressure + "\n"
//                                    + "lowPressure:" + lowPressure + "\n"
//                                    + "pulseWave" + pulseWave + "\n"
//                                    + "ahr:" + ahr + "\n"
//                                    + "hsd:" + hsd + "\n";
                      }
                  }
                  Message msg = new Message();
                  msg.what = HANDLER_MESSAGE;
                  msg.obj = map;
                  myHandler.sendMessage(msg);
              } catch (JSONException e) {
                  e.printStackTrace();
              }

          } else if (BpProfile.ACTION_HISTORICAL_NUM_BP.equals(action)) {
              try {
                  JSONObject info = new JSONObject(message);
                  String num = info.getString(BpProfile.HISTORICAL_NUM_BP);
                  Message msg = new Message();
                  msg.what = HANDLER_MESSAGE;
                  Map<String, String> map = new HashMap<>();
                  map.put("num", num);
                  msg.obj = map;
//                    msg.obj = "num: " + num;
                  myHandler.sendMessage(msg);
              } catch (JSONException e) {
                  e.printStackTrace();
              }

          } else if (BpProfile.ACTION_IS_ENABLE_OFFLINE.equals(action)) {
              try {
                  JSONObject info = new JSONObject(message);
                  String isEnableoffline = info.getString(BpProfile.IS_ENABLE_OFFLINE);
                  Message msg = new Message();
                  msg.what = HANDLER_MESSAGE;
                  Map<String, String> map = new HashMap<>();
                  map.put("isEnableoffline", isEnableoffline);
                  msg.obj = map;
//                    msg.obj = "isEnableoffline: " + isEnableoffline;
                  myHandler.sendMessage(msg);
              } catch (JSONException e) {
                  e.printStackTrace();
              }

          } else if (BpProfile.ACTION_ONLINE_PRESSURE_BP.equals(action)) {
              try {
                  JSONObject info = new JSONObject(message);
                  String pressure = info.getString(BpProfile.BLOOD_PRESSURE_BP);
                  Message msg = new Message();
                  msg.what = HANDLER_MESSAGE;
                  Map<String, String> map = new HashMap<>();
                  map.put("pressure", pressure);
                  msg.obj = map;
//                    msg.obj = "pressure: " + pressure;
                  myHandler.sendMessage(msg);
              } catch (JSONException e) {
                  e.printStackTrace();
              }

          } else if (BpProfile.ACTION_ONLINE_PULSEWAVE_BP.equals(action)) {
              try {
                  JSONObject info = new JSONObject(message);
                  String pressure = info.getString(BpProfile.BLOOD_PRESSURE_BP);
                  String wave = info.getString(BpProfile.PULSEWAVE_BP);
                  String heartbeat = info.getString(BpProfile.FLAG_HEARTBEAT_BP);
                  Message msg = new Message();
                  msg.what = HANDLER_MESSAGE;
                  Map<String, String> map = new HashMap<>();
                  map.put("pressure", pressure);
                  map.put("wave", wave);
                  map.put("heartbeat", heartbeat);
                  msg.obj = map;
//                    msg.obj = "pressure:" + pressure + "\n"
//                            + "wave: " + wave + "\n"
//                            + " - heartbeat:" + heartbeat;
                  myHandler.sendMessage(msg);
              } catch (JSONException e) {
                  e.printStackTrace();
              }

          } else if (BpProfile.ACTION_ONLINE_RESULT_BP.equals(action)) {
              try {
                  JSONObject info = new JSONObject(message);
                  String highPressure = info.getString(BpProfile.HIGH_BLOOD_PRESSURE_BP);
                  String lowPressure = info.getString(BpProfile.LOW_BLOOD_PRESSURE_BP);
                  String ahr = info.getString(BpProfile.MEASUREMENT_AHR_BP);
                  String pulse = info.getString(BpProfile.PULSE_BP);
                  Message msg = new Message();
                  msg.what = HANDLER_MESSAGE;
                  Map<String, String> map = new HashMap<>();
                  map.put("highPressure", highPressure);
                  map.put("lowPressure", lowPressure);
                  map.put("ahr", ahr);
                  map.put("pulse", pulse);
                  msg.obj = map;
//                    msg.obj = "highPressure: " + highPressure
//                            + "lowPressure: " + lowPressure
//                            + "ahr: " + ahr
//                            + "pulse: " + pulse;
                  myHandler.sendMessage(msg);
              } catch (JSONException e) {
                  e.printStackTrace();
              }

          } else if (BpProfile.ACTION_ZOREING_BP.equals(action)) {
              Message msg = new Message();
              msg.what = HANDLER_MESSAGE;
              Map<String, String> map = new HashMap<>();
              map.put("zoreing", "Starting..");
              msg.obj = map;
//                msg.obj = "zoreing";
              myHandler.sendMessage(msg);

          } else if (BpProfile.ACTION_ZOREOVER_BP.equals(action)) {
              Message msg = new Message();
              msg.what = HANDLER_MESSAGE;
              Map<String, String> map = new HashMap<>();
              map.put("zoreover", "Completing..");
              msg.obj = map;
//                msg.obj = "zoreover";
              myHandler.sendMessage(msg);

          } else if (BpProfile.ACTION_STOP_BP.equals(action)) {
              Message msg = new Message();
              msg.what = HANDLER_MESSAGE;
              Map<String, String> map = new HashMap<>();
              map.put("stopmeasure", "stop measure from device");
              msg.obj = map;
//                msg.obj = "stop measure from device";
              myHandler.sendMessage(msg);

          }
      }
  };

Handler code:

private static final int HANDLER_MESSAGE = 101;
Handler myHandler = new Handler() {
  public void handleMessage(Message msg) {
      switch (msg.what) {
          case HANDLER_MESSAGE:
              Map<String, String> map = (Map<String, String>) msg.obj;
              if (map.get("zoreing") != null && !map.get("zoreing").isEmpty()) {
                  reading.setText(map.get("zoreing"));
              } else if (map.get("pressure") != null && !map.get("pressure").isEmpty())
                  reading.setText(map.get("pressure"));
              else if (map.get("highPressure") != null && !map.get("highPressure").isEmpty()
                      && map.get("lowPressure") != null && !map.get("lowPressure").isEmpty()
                      && map.get("pulse") != null && !map.get("pulse").isEmpty()) {
                  reading.setText(getResources().getString(R.string.label_complete));
                  bpMeasurement.setSystolic(Double.parseDouble(map.get("highPressure")));
                  bpMeasurement.setDiastolic(Double.parseDouble(map.get("lowPressure")));
                  pulseMeasurement.setValue(Double.parseDouble(map.get("pulse")));
                  bpMeasurement.setMeasuredAt(new Date());
                  pulseMeasurement.setMeasuredAt(new Date());

                  // enable getResult Button
                  getResult.setText(R.string.label_get_result);
                  getResult.setEnabled(true);
              }
              break;
      }
      super.handleMessage(msg);
  }
};


Step 4:

Unregister on destoy:

iHealthDevicesManager.getInstance().unRegisterClientCallback(clientCallbackId);




 

Comments

Popular posts from this blog

Deploy Spring Boot app in digitalocean cloud (or any cloud as long asyou have ssh access)

Upload large files : Spring Boot

User activity logging: Spring