Empalink例程阅读

Empallink-sample-project-android-master

功能介绍

  • 搜索E4手环
  • 连接设备
  • 采集10s的数据
  • 断开连接

使用方法

  • 下载Github源码
  • 在MainActivity.java的EMPATICA_KEY中输入设备的API码
  • 导入.aar依赖包
  • 编译运行
  • 打开设备,进行连接

代码分析

导入依赖库:

import com.empatica.empalink.ConnectionNotAllowedException;
import com.empatica.empalink.EmpaDeviceManager; // 有关设备搜索、连接、API检验
import com.empatica.empalink.EmpaticaDevice; // 设备信息
import com.empatica.empalink.config.EmpaSensorStatus;// 注释类型:是否在手腕上
import com.empatica.empalink.config.EmpaSensorType; //枚举类型:传感器类型 
import com.empatica.empalink.config.EmpaStatus; //枚举类型:连接状态
import com.empatica.empalink.delegate.EmpaDataDelegate; // 实例:接收设备的电量、传感器数据、时间戳
import com.empatica.empalink.delegate.EmpaStatusDelegate;// 实例:接受EmpaDeviceManager的信息

主程序派生于AppCompatActivity,是EmpaDataDelegate和EmpaStatusDelegate的实例,首先定义了一些变量。

private static final int REQUEST_ENABLE_BT = 1;
private static final int REQUEST_PERMISSION_ACCESS_COARSE_LOCATION = 1;
private static final String EMPATICA_API_KEY = "ee75b37389644a73b301767a4c0972e2"; 
/* EMPATICA_API_KEY从E4官网的账号中获得,再将我们购买的设备录入 */
private EmpaDeviceManager deviceManager = null;

private TextView accel_xLabel;
private TextView accel_yLabel;
private TextView accel_zLabel;

private TextView bvpLabel;
private TextView edaLabel;
private TextView ibiLabel;
private TextView temperatureLabel;

private TextView batteryLabel;
private TextView statusLabel;
private TextView deviceNameLabel;
private LinearLayout dataCnt;

接下来是一堆重写的函数:

/* 初始化与xml元素相对应的变量,设置按钮的功能,调用initEmpaticaDeviceManager() */
@Override
protected void onCreate(Bundle savedInstanceState)

/* 判断是否得到使用BLE的权利 */
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)

/* 请求使用BLE,检查API_KEY是否为空 */
private void initEmpaticaDeviceManager()    

/* 设置活动的生命周期 */    
@Override
protected void onPause()
        
/* 设置活动的生命周期 */     
@Override
protected void onDestroy()

/* 判断当前设备能否与API_KEY匹配。若匹配,停止搜索,更新设备ID */
@Override
public void didDiscoverDevice(EmpaticaDevice bluetoothDevice, String deviceName, int rssi, boolean allowed)

/* 当发现蓝牙被关闭时,请求用户开启蓝牙 */
@Override
public void didRequestEnableBluetooth() 

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)

/* 调用didUpdateOnWristStatus*/    
@Override
public void didUpdateSensorStatus(@EmpaSensorStatus int status, EmpaSensorType type)

/* 更新设备的连接状态 */
@Override
public void didUpdateStatus(EmpaStatus status)

/* 更新各个传感器的参数 */
@Override
public void didReceiveAcceleration(int x, int y, int z, double timestamp)
    
@Override
public void didReceiveBVP(float bvp, double timestamp)
    
@Override
public void didReceiveBatteryLevel(float battery, double timestamp)
    
@Override
public void didReceiveGSR(float gsr, double timestamp)
    
@Override
public void didReceiveIBI(float ibi, double timestamp)
    
@Override
public void didReceiveTemperature(float temp, double timestamp)
    
private void updateLabel(final TextView label, final String text)
    
@Override
public void didReceiveTag(double timestamp)
    
@Override
public void didEstablishConnection()
    
/* 更新UI界面里手腕检测值 */
@Override
public void didUpdateOnWristStatus(@EmpaSensorStatus final int status)
    
void show()
    
void hide()

但是整个程序的驱动器在哪里啊。。

好像不太熟悉Java的运行方式。

代码修改

  • 根据IBI参数(ECG间期时长)计算心率,替代IBI,显示在UI界面上;
    HR=\frac{60}{IBI}
  • 在UI界面上显示TimeStamp,新建TextView控件,在didReceiveAcceleratioin函数中更新TimeStamp的值。
    /*
     MainActivity.java
    */
     @Override
     public void didReceiveAcceleration(int x, int y, int z, double timestamp) {
     updateLabel(accel_xLabel, "" + x);
     updateLabel(accel_yLabel, "" + y);
     updateLabel(accel_zLabel, "" + z);
     updateLabel(time_stamp, "" + timestamp);
     }
    ​
    /*
     activity_main.xml
    */
     <TextView
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_below="@id/wrist_status_label"
     android:text="timeStamp" />
    ​
     <TextView
     android:id="@+id/timeStamp"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_below="@id/wrist_status_label"
     android:width="50dp"
     android:text="@string/emptyText" />

出现的问题是:显示的timestamp值是一个很长位数的数字,需要在开始更新状态时设置一个初始值作为0基准值,该基准值为当前时间到1970年1月1日00:00:00的秒数,所以我们需要获取当前设备的时间.为此,查阅资料发现java自带的函数System.currentTimeMills()可以返回当前距离基准时间的值(且精度高了3位)修改后的代码可以实现以程序运行时作为基准时。

private double initTimeStamp = (double)System.currentTimeMillis() / 1000;
​
 @Override
 public void didReceiveAcceleration(int x, int y, int z, double timestamp) {
 updateLabel(accel_xLabel, "" + x);
 updateLabel(accel_yLabel, "" + y);
 updateLabel(accel_zLabel, "" + z);
 updateLabel(time_stamp, "" + (timestamp - initTimeStamp));
 }

将数值显示转换成波形显示

为了避免程序无法响应,使用基于SurfaceView控件的方式进行作图,相当于在主线程中开启了一个子线程进行绘图缓冲,每次绘图完成后就终止子线程。

由于界面大小限制,先只绘制Temperature的波形图。

首先新建一个mView类,继承于View类,在上面进行背景网格的绘制和波形曲线的绘制。

  • 背景网格绘制:
    设置画笔颜色、粗细:
          private Paint mPaint;
          private Path mPath = new Path();
          int mBackgroundColor = Color.WHITE;
          int mTextColor = Color.BLUE;
          int mGridColor = Color.GRAY;
          int mPointColor = Color.RED;
          int mLineColor = Color.RED;
          int hNum = 6;
      
          float data = 0;
          int xMove = 20;
          int x = 0;
          float y;
      
          boolean isFull = true;
      
          public mView(Context context, AttributeSet attrs) {
              super(context, attrs);
              mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
          }

重载onDraw函数:

          @Override
          protected void onDraw(Canvas canvas) {
              mPaint.setColor(mBackgroundColor);
              canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
      
              mPaint.setColor(mTextColor);
              mPaint.setTextSize(40);
              String text = "Temp Curve";
              //canvas.drawText(text, 0, 40, mPaint);
      
              mPaint.setColor(mGridColor);
              for(int i=0; i < hNum+1; i++) {
                  canvas.drawLine(0, i * getHeight()/hNum, getWidth(), 5 + i * getHeight()/hNum, mPaint);
              }
      
              mPaint.setColor(mPointColor);
              mPaint.setStrokeWidth(10);
              for(int i = 0; i < getWidth(); i++) {
                  canvas.drawPoint(i, i * getHeight()/getWidth(), mPaint);
              }
          }
  • 波形曲线绘制:
    接收E4手环传过来的数据:
          /** Send data into mView **/
          public void setListData(float newData) {
              data = newData;
          }

坐标映射:

          /** Axis transform **/
          public float axisTrans(float data) {
              float y;
              float Rmin = 30;
              float Rmax = 36;
              float mHeight = 120;
      
              y = -2 * data + 240;
              return y;
          }

曲线绘制:

          /** Draw curve **/
          public void drawCurve(Canvas canvas) {
              /** No data Recieved **/
              if (data == 0) {
                  return;
              }
              y = axisTrans(data);
              if (x > getWidth()) {
                  x = 0;
                  mPath.reset();
                  mPath.moveTo(0, y);
              }
              x += xMove;
              mPath.lineTo(x, y);
      
              mPaint.setColor(mLineColor);
              mPaint.setStrokeWidth(10);
              mPaint.setStyle(Paint.Style.STROKE);
              canvas.drawPath(mPath, mPaint);
          }

第二步:在xml中部署画布:

            <com.empatica.sample.mView
                android:id="@+id/waveform"
                android:layout_width="wrap_content"
                android:layout_height="120dp" />

第三步:在MainActivity中的didRecievedXXX()中将收到的E4手环数据发送到mView中,刷新页面,进行波形的显示。

            /** Send data to canvas and update UI **/
            waveForm.setListData(temp);
            waveForm.postInvalidate();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,576评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,515评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,017评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,626评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,625评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,255评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,825评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,729评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,271评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,363评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,498评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,183评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,867评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,338评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,458评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,906评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,507评论 2 359

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,699评论 18 139
  • 在推荐年轻客户办理信用卡的过程中,柜台的小伙伴们普遍反应了一个客户的心结,那就是担心办理了信用卡以后影响自己...
    汉典阅读 107评论 0 0
  • 你有没有这样的感觉? 宝宝吃饭磨磨蹭蹭,饭菜一热再热 答应马上睡觉,结果还能玩1个小时 内心os: 小宝贝哟! 你...
    LI英阅读 180评论 0 0
  • 今天我的任务是写够1万字,现在已经完成了三千,我就在想这剩余的7000字儿怎么写? 先说说天气吧,早上的时候因为我...
    圈圈o0阅读 644评论 0 0
  • 人生就是如此的奇妙,当你选择了一条路的时候,你永远不会知道它是否是正确的,若你当初选择了另一条路是怎样的结果。所以...
    菲柯夜语阅读 112评论 0 0