Android 方面:
IBM Bluemix 方面:
回页首
首先,创建一个新的 Android 项目 (File->New->New Project)。
在向导中,键入“HeartRate”作为应用程序名称并选择您的项目所在的位置。
单击“Next”,选择“Phone and Tablet”和“Wear”,然后根据您的设备选择最低限度的 SDK。
单击“Next”,为移动应用程序选择“Blank Activity”。
单击“Next”,在 Activity Name 字段中键入“HeartRateMobileActivity”。
单击“Next”,为 Wear 应用程序选择“Blank Wear Activity”。
单击“Next”,在 Activity Name 字段中键入“HeartRateWearActivity”。
单击“Finish”。
回页首
确保“mobile”和“wear”清单文件具有“BODY_SENSOR”权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ibm.hcs.heartrate" > <uses-permission android:name="android.permission.BODY_SENSORS" /> …
在“wear”string.xml 文件中添加一个标签:
<string name="heartRateText">Heart Rate : N/A</string>
打开 Wear 的布局“round_activity_heart_rate_wear.xml”,然后使用“heartRateTextView”更改“id”字段,并使用 “@string/heartRateText”更改“text”字段。
打开“HeartRateWearActivity”字段并更改“onCreate”函数。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_heart_rate_wear); final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { @Override public void onLayoutInflated(WatchViewStub stub) { mTextView = (TextView) stub.findViewById(R.id.heartRateTextView); } }); }
创建一个名为“HeartRateWearService”的服务,验证清单文件:
<service android:name=".HeartRateWearService">
使用以下代码替换生成的文件:
点击查看代码清单
关闭 [x]
public class HeartRateWearService extends Service implements SensorEventListener{ private SensorManager sensorManager; private Sensor heartRateSensor; private ScheduledExecutorService heartRateScheduler; public HeartRateWearService() { } @Override public void onCreate() { super.onCreate(); getHeartRateValues(); } private void getHeartRateValues() { sensorManager = ((SensorManager) getSystemService(SENSOR_SERVICE)); heartRateSensor = sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE); if (heartRateSensor != null) { heartRateScheduler = Executors.newScheduledThreadPool(1); heartRateScheduler.scheduleAtFixedRate( new Runnable() { @Override public void run() { sensorManager.registerListener(HeartRateWearService.this, heartRateSensor, SensorManager.SENSOR_DELAY_NORMAL); try { Thread.sleep(10000); } catch (InterruptedException e) { } sensorManager.unregisterListener(HeartRateWearService.this,heartRateSensor); } }, 3, 15, TimeUnit.SECONDS); } } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { if (sensorManager != null) sensorManager.unregisterListener(this); heartRateScheduler.shutdown(); super.onDestroy(); } @Override public void onSensorChanged(SensorEvent event) { // sends an Intent to the Activity Intent intent = new Intent(); intent.setAction("heartRateAction"); intent.putExtra("HeartRate", event.values[0]); sendBroadcast(intent); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { }
打开“HeartRateWearActivity”文件,添加此属性:
private HeartRateBroadcastReceiver heartRateBroadcastReceiver;
添加此内部类:
private class HeartRateBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context arg0, Intent arg1) { // ahr Log.v(this.getClass().getName(), "Value Recieved"); if (arg1.getAction().equals("heartRateAction")) { float hr = arg1.getFloatExtra("HeartRate", 0); if (HeartRateWearActivity.this.mTextView != null) { HeartRateWearActivity.this.mTextView.setText("Heart Rate : " + hr); } } } }
添加以下方法:
@Override protected void onStart() { // initialize the broadcast recieiver heartRateBroadcastReceiver = new HeartRateBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("heartRateAction"); registerReceiver(heartRateBroadcastReceiver, intentFilter); // start HeartRateWearService startService(new Intent(this, HeartRateWearService.class)); super.onStart(); } @Override protected void onStop() { unregisterReceiver(heartRateBroadcastReceiver); stopService(new Intent(this, HeartRateWearService.class)); super.onStop(); }
回页首
打开“HeartRateWearService”,添加属性:
private GoogleApiClient googleApiClient; private ExecutorService executorService;
在“onCreate”函数中初始化 executorService:
@Override public void onCreate() { … … executorService = Executors.newCachedThreadPool(); }
添加以下函数:
点击查看代码清单
关闭 [x]
private boolean isConnected() { if (googleApiClient == null) googleApiClient = new GoogleApiClient.Builder(this.getApplication().getApplicationContext()).addApi(Wearable.API).build(); if (googleApiClient.isConnected()) { return true; } ConnectionResult result = googleApiClient.blockingConnect(15000, TimeUnit.MILLISECONDS); return result.isSuccess(); } private void sendToMobile(final SensorEvent event) { executorService.submit(new Runnable() { @Override public void run() { PutDataMapRequest dataMap = PutDataMapRequest.create("/sensor/heartRate"); dataMap.getDataMap().putLong("timestamp", event.timestamp); dataMap.getDataMap().putFloat("value", event.values[0]); PutDataRequest putDataRequest = dataMap.asPutDataRequest(); if (isConnected()) { Wearable.DataApi.putDataItem(googleApiClient, putDataRequest).setResultCallback(new ResultCallback<DataApi.DataItemResult>() { @Override public void onResult(DataApi.DataItemResult dataItemResult) { Log.v(this.getClass().getName(), "Sending heartRate: " + dataItemResult.getStatus().isSuccess()); } }); } } }); }
在“onSensorChanged”函数中添加此指令:
@Override public void onSensorChanged(SensorEvent event) { … … sendToMobile(event); }
在“mobile”string.xml 文件中添加一个标签:
<string name="heartRateText">Heart Rate : N/A</string>
打开移动布局“activity_heart_rate_mobile.xml”,然后使用“heartRateTextView”更改“id”字段,并使用 “@string/heartRateText”更改“text”字段。
在移动模块中创建一个新服务“HeartRateMobileWearableListenerService”。
更新移动清单:
<service android:name=".HeartRateMobileWearableListenerService" > <intent-filter> <action android:name="com.google.android.gms.wearable.BIND_LISTENER"/> </intent-filter> </service>
更改“HeartRateMobileWearableListenerService”代码:
public class HeartRateMobileWearableListenerService extends WearableListenerService { @Override public void onDataChanged(DataEventBuffer dataEvents) { Log.d(this.getClass().getName(), "onDataChanged()"); for (DataEvent dataEvent : dataEvents) { if (dataEvent.getType() == DataEvent.TYPE_CHANGED) { DataItem dataItem = dataEvent.getDataItem(); Uri uri = dataItem.getUri(); String path = uri.getPath(); if (path.equals("/sensor/heartRate")) { DataMap map = DataMapItem.fromDataItem(dataItem).getDataMap(); long timestamp = map.getLong("timestamp"); float value = map.getFloat("value"); Intent intent = new Intent(); intent.setAction("heartRateAction"); intent.putExtra("HeartRate", value); sendBroadcast(intent); } } } } }
打开“HeartRateMobileActivity”,添加此属性:
private HeartRateBroadcastReceiver heartRateBroadcastReceiver;
添加此内部类:
点击查看代码清单
关闭 [x]
private class HeartRateBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context arg0, Intent arg1) { // ahr Log.v(this.getClass().getName(), "Value Recieved"); if (arg1.getAction().equals("heartRateAction")) { float hr = arg1.getFloatExtra("HeartRate", 0); ((TextView)HeartRateMobileActivity.this.findViewById(R.id.heartRateTextView)).setText("Heart Rate : " + hr); } } }
添加“onStart”函数:
@Override protected void onStart() { super.onStart(); // ahr heartRateBroadcastReceiver = new HeartRateBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("heartRateAction"); registerReceiver(heartRateBroadcastReceiver, intentFilter); }
回页首
添加 mqtt 服务:
<service android:name="org.eclipse.paho.android.service.MqttService" />
添加 WAKE_LOCK 权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
创建新的 MqttHandler 类,复制以下代码并更改组织和设备令牌:
public class MqttHandler implements MqttCallback { private static MqttHandler instance; private MqttAndroidClient mqttClient; Context context; private static String ORG = "YOUR_IOT_ORGANISATION"; private static String DEVICE_TYPE = "Wear"; private static String DEVICE_ID = "myWatch"; private static String TOKEN = "YOUR_DEVICE_TOKEN"; private static String TOPIC = "iot-2/evt/hr/fmt/json"; private MqttHandler(Context context) { this.context = context; } public static MqttHandler getInstance(Context context) { if (instance == null) { instance = new MqttHandler(context); } return instance; } @Override public void connectionLost(Throwable throwable) { } @Override public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception { } @Override public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { } public void connect(IMqttActionListener listener) { if (!isConnected()) { String iotPort = "1883"; String iotHost = ORG+".messaging.internetofthings.ibmcloud.com"; String iotClientId = "d:"+ORG+":"+DEVICE_TYPE+":"+DEVICE_ID; String connectionUri = "tcp://" + iotHost + ":" + iotPort; if (mqttClient != null) { mqttClient.unregisterResources(); mqttClient = null; } mqttClient = new MqttAndroidClient(context, connectionUri, iotClientId); mqttClient.setCallback(this); MqttConnectOptions options = new MqttConnectOptions(); options.setCleanSession(true); options.setUserName("use-token-auth"); options.setPassword(TOKEN.toCharArray()); try { mqttClient.connect(options, context, listener); } catch (MqttException e) { } } } public void disconnect(IMqttActionListener listener) { if (isConnected()) { try { mqttClient.disconnect(context, listener); mqttClient = null; } catch (MqttException e) { e.printStackTrace(); } } } public void publish(long timestamp, float heartRateValue) { if (isConnected()) { String msg = "{'timestamp':"+timestamp+",'heartRate':"+heartRateValue+"}"; MqttMessage mqttMsg = new MqttMessage(msg.getBytes()); mqttMsg.setRetained(false); mqttMsg.setQos(0); try { mqttClient.publish(TOPIC, mqttMsg); } catch (Exception e) { } } } private boolean isConnected() { if (mqttClient != null) { return mqttClient.isConnected(); } return false; } }
打开 HeartRateMobileActivity,添加此属性:
private boolean connected = false;
在 onStart 函数的末尾处添加此代码:
MqttHandler.getInstance(this).connect(new IMqttActionListener() { @Override public void onSuccess(IMqttToken iMqttToken) { connected = true; } @Override public void onFailure(IMqttToken iMqttToken, Throwable throwable) { } });
在 onStop 函数的开头处添加此代码:
MqttHandler.getInstance(this).disconnect(new IMqttActionListener() { @Override public void onSuccess(IMqttToken iMqttToken) { connected = false; } @Override public void onFailure(IMqttToken iMqttToken, Throwable throwable) { } });
使用下列代码更新 onReceive 函数:
点击查看代码清单
关闭 [x]
public void onReceive(Context arg0, Intent arg1) { // ahr Log.v(this.getClass().getName(), "Value Recieved"); if (arg1.getAction().equals("heartRateAction")) { float hr = arg1.getFloatExtra("HeartRate", 0); long ts = arg1.getLongExtra("timestamp", 0); ((TextView)HeartRateMobileActivity.this.findViewById(R.id.heartRateTextView)).setText("Heart Rate : " + hr); if (connected) MqttHandler.getInstance(HeartRateMobileActivity.this).publish(ts, hr); } }
回页首
打开 IoT Fundation Dashboar,选择“Access”和“API Key”,然后生成一个新的 API 秘钥。
将秘钥和身份验证令牌保存在一个文件中。
打开 IBM Bluemix dashboard,然后打开 Catalog 并选择“IoT Real-Time Insights”。
单击“USE”按钮。
单击“Add a data source”按钮,单击“Add New data source”,然后键入 IoT Fundation 组织令牌和 API 秘钥/身份验证令牌。
验证,选择“Devices”和“Browse Devices”,然后就会看到您的 IoT 设备。
选择“Manage Schemas”,然后选择“Add new message schema”。键入一个名称并链接一个新的数据源。选择 IoT Hear Rate 数据源和 “Wear”类型,然后进行验证。
添加新的数据点。
验证。
选择“Analytics”,然后选择“Add new rule”,键入名称和描述。
添加一个条件。
通过单击来编辑条件“Heart Rate greater than 120 b/m”。
验证,通过单击来编辑动作“Send an email to …”并进行验证,然后您必须激活该规则。
选择“Dashboards”和“Browse Dashboards”,然后选择“Add new Dashboard”,键入仪表板名称并进行验证。
选择仪表板并添加以下组件:
1) 一个 Text 组件
2) 一个带有心率线的 Chart 组件
3) 一个映射到 myWatch 的 Device 组件
4) 一个带有警告组件的 Filtered Devices 组件
5) 一个用于设备组件的 Alert 组件
结果:
现在,在启动 Android Wear 应用程序时,就可以在 Chart 组件和 Device 组件中看到实时心率值。如果心率大于 120,就会收到警报电子邮件,并在 Alert 组件中查看具体情况。