nativescript-wearos-sensors
插件,用于开发智能手机应用程序,可从配对的WearOS智能手表接收传感器数据。
npm i --save nativescript-wearos-sensors

nativescript-wearos-sensors

npm npm

nativescript-wearos-sensors 是使用 NativeScript 框架开发的插件。它允许开发智能手机应用程序,用于从配对的Android WearOS智能手表(如果设备中存在相应的传感器)收集IMU传感器(例如加速度计和陀螺仪)、磁力计、心率以及GPS数据。

Android WearOS智能手表必须运行使用本地 WearOS Sensors 库构建的对应应用程序。然后,智能手机应用程序可以请求智能手表开始/停止指定传感器的数据收集,智能手表将收集到的样本发送到智能手机应用程序。

[!WARNING] 如果配对的智能手表中没有使用 WearOS Sensors 库构建的对应应用程序,使用此插件的应用程序将完全无用。换句话说,智能手机不能独立工作。它需要一个智能手表才能工作。

数据收集可以从智能手机和配对的智能手表启动。此外,该插件提供了一种通过发送消息与智能手表通信的方式。

安装

在您的项目根目录中运行以下命令。

ns plugin add nativescript-wearos-sensors

要求

此插件仅由 Android 智能手机支持。要使用它构建应用程序,必须满足以下要求

  • 运行 Android 6(API 级别 23)或更高版本的 Android 智能手机。

[!CAUTION] 构建的应用程序的 targetSdkVersion 必须小于或等于 31(Android 12)。针对 >=31 的应用程序将无法工作,因为 Dynamic File Loading 存在问题。

  • 此外,智能手机必须与安装有对应应用程序的智能手表配对。要将智能手表连接到智能手机,您还必须安装 Google Smartwatch WearOS 或智能手表制造商提供的特定应用程序(例如,Mobvoi Health、Samsung Wearable 等),并按照连接两个设备的说明进行操作。

[!IMPORTANT] 两个应用程序(智能手机和智能手表应用程序)必须具有相同的应用程序 id。如果不是这样,应用程序将无法交互。您可以在 nativescript.config.ts 中更改 NativeScript 应用程序的应用程序 id。

使用方法

该插件提供以下功能

首先,您需要使用 WearosSensorsConfig 在您的 app.ts(TypeScript 应用程序)或 main.ts(Angular 应用程序)文件中初始化插件

// TypeScript App:
import { Application } from "@nativescript/core";
// or Angular App:
import { platformNativeScriptDynamic } from "nativescript-angular/platform";
import { AppModule } from "./app/app.module";

// WearOSSensors import
import { wearosSensors, allSensors } from "nativescript-wearos-sensors";

wearosSensors.init({
sensors: allSensors,
disablePlainMessaging: false,
disableWearCommands: false
});

// TypeScript App:
Application.run({ moduleName: "app-root" });
// Angular App:
platformNativeScriptDynamic().bootstrapModule(AppModule);

初始化参数是可选的,允许指定哪些传感器已启用(sensors),以及是否启用 PlainMessaging(《disablePlainMessaging》)和 WearCommands(《disableWearCommands》)功能。默认配置是上面示例中显示的配置:所有传感器和功能都启用。

[!注意] 此配置允许根据条件将本地组件与插件核心连接。这可以减少应用程序在未使用某些功能时使用的内存。

传感器数据收集

如上所述,数据收集可以由两个设备启动/停止,但只有智能手机可以访问收集到的数据。

要接收收集到的数据,智能手机必须通过 CollectorManager 注册监听器(至少一个)。可以为特定的节点/(例如,智能手表)和特定的传感器/设置监听器。这意味着可以有多个注册的监听器,它们都监听不同的节点或传感器。可以使用 ListenerFilters 实现此行为。以下是如何注册不同监听器的示例

import { getCollectorManager } from "nativescript-wearos-sensors/collection";
import { SensorRecord } from "nativescript-wearos-sensors/sensors/records";
import { Node } from "nativescript-wearos-sensors/node";
import { ListenerFilter } from "nativescript-wearos-sensors/listeners";
import { SensorType } from "nativescript-wearos-sensors/sensors";


function registerGlobalListener() {
// Register a listener witout filters --> receives records from all sources
getCollectorManager().addSensorListener((sensorRecord: SensorRecord<any>) => {
console.log(deviceId, JSON.stringify(sensorRecord))
;
});
}

function registerListenerForNode(node: Node) {
// Register a listener filtering per node --> receives all kind of records from that node
const filter: ListenerFilter = {
nodes: [node]
}
getCollectorManager().addSensorListener((sensorRecord: SensorRecord<any>) => {
console.log(deviceId, JSON.stringify(sensorRecord))
;
}, filter);
}

function registerListenerForSensor(sensor: SensorType) {
// Register a listener filtering per sensor --> receives records of that sensor from any node
const filter: ListenerFilter = {
sensors: [sensor]
}
getCollectorManager().addSensorListener((sensorRecord: SensorRecord<any>) => {
console.log(deviceId, JSON.stringify(sensorRecord))
;
}, filter);
}

function registerListenerForNodeAndSensors(node: Node, sensors: SensorType[]) {
// Register a listener filtering per node and sensor --> receives records of that sensors from that node
const filter: ListenerFilter = {
nodes: [node],
sensors: sensors
}
getCollectorManager().addSensorListener((sensorRecord: SensorRecord<any>) => {
console.log(deviceId, JSON.stringify(sensorRecord))
;
}, filter);
}

从智能手机开始/停止数据收集

为了开始节点的数据收集,首先您必须使用 NodeDiscoverer 获取连接的节点。一旦您获得连接的节点,您就必须遵循一些步骤来开始数据收集

  1. 检查节点上的特定传感器是否已准备好进行收集。
  2. 如果它没有准备好
    1. 这是因为传感器未在设备中。
    2. 传感器在设备中,但智能手表应用程序没有收集该传感器的权限。
  3. 如果我们缺乏权限,我们可以只是要求用户授予它们。
    1. 如果权限被拒绝,那就到此为止了...
    2. 如果权限被授予,我们可以开始收集!!

要开始数据收集,我们还应该指定一个 CollectionConfiguration,其中我们可以指定连续样本之间的所需时间(sensorDelay)以及每次交付的样本数量(batchSize)。配置是可选的,如果未提供配置,则应用默认值。

[!注意] 由于智能手表必须通过蓝牙发送收集到的数据,因此在与高采样率一起工作时,我们无法发送单个样本。这样会饱和连接。为了解决这个问题,我们以批量的方式发送样本。

以下是此收集程序的示例

import { getNodeDiscoverer } from "nativescript-wearos-sensors/node";
import { getCollectorManager, PrepareError, CollectionConfiguration } from "nativescript-wearos-sensors/collection";
import { Node } from "nativescript-wearos-sensors/node";
import { SensorType } from "nativescript-wearos-sensors/sensors";

async function getNodes(): Promise<Node[]> {
await nodesDiscovered = nodeDiscoverer.getConnectedNodes();
const nodes = []
nodesDiscovered.forEach((nodeDiscovered) => {
if (nodeDiscovered.error) {
this.logger.logResult(nodeDiscovered.error);
return;
}
nodes.push(nodeDiscovered.node);
});
return nodes;
}

async function collectFrom(node: Node, sensor: SensorType, config: CollectionConfiguration) {
const collectorManager = getCollectorManager();

const isReady = await collectorManager.isReady(node, sensor);
if (!isReady) {
const prepareError: PrepareError = await collectorManager.prepare(node, sensor);
if (prepareError) {
console.log(prepareError.message);
return;
}
}

await collectorManager.startCollecting(node, sensor, config);
}

async function stopCollecingFrom(node: Node, sensor: SensorType) {
await collectorManager.stopCollecting(node, sensor);
}

从智能手表开始/停止数据收集

插件为您完全处理此问题。您只需确保至少注册一个监听器以接收收集到的数据。

[!重要] WearCommands功能必须在插件初始化时启用。

普通消息传递

在一个由多个设备组成的系统中,有一种方法来进行通信很重要。我们提供了 PlainMessageClient,它允许发送和接收基于字符串的消息。有两种类型接收到的消息:需要响应的消息和不需要响应的消息。以下是如何使用消息功能的示例

import { getPlainMessageClient } from "src/internal/communication/plain-message";

function registerListener(): void {
// Register a listener to receive messages from the smartwatch
getPlainMessageClient().registerListener((receivedMessage) => {
console.log(`received single message ${JSON.stringify(receivedMessage)}`);
});
}

async function sendMessage(node: Node, message: string): void {
// Send a message to the smartwatch
const plainMessage = {message: "You don't have to reply :)"};
await getPlainMessageClient().send(node, plainMessage);
}

async function sendMessageAndWaitResponse(node: Node, message: string): void {
// Send a message to the smartwatch and wait for a response
const plainMessage = {message: "PING!"};
const receivedMessage = await getPlainMessageClient().sendExpectingResponse(node, plainMessage);
console.log(`response received: ${JSON.stringify(receivedMessage)}`);
}

[!重要] 平凡消息传递功能必须在插件初始化时启用。

API

wearosSensors - 方法

名称 返回类型 描述
init(config?: WearosSensorsConfig) Promise<void> 根据提供的配置初始化本地组件。如果没有提供配置,则默认为 defaultConfig

WearosSensorsConfig

属性 类型 描述
sensors? SensorType[] 将要使用的传感器。默认:所有传感器。
disablePlainMessaging? boolean 禁用普通消息传递功能。默认:false。
disableWearCommands? boolean Disable wear commands feature. Default: false.
defaultConfig
export const defaultConfig = {
sensors: allSensors, // Constant containing all the sensors
disablePlainMessaging: false,
disableWearCommands: false
};

NodeDiscoverer

函数 返回类型 描述
getLocalNode() Promise<Node> 获取本地节点的引用(智能手机)。
areConnectedNodes() Promise<boolean> 如果存在连接的节点,则返回 true。
getConnectedNodes(timeout: number = 5000) Promise<NodeDiscovered[]> 获取当前连接的节点及其可用的传感器。超时指示连接节点与智能手机通信的最大等待时间。

Node

字段 类型 描述
名称 字符串 设备名称。
id 字符串 设备的ID号码。
功能 SensorType[] 设备上可用的传感器。

NodeDiscovered

字段 类型 描述
节点 Node 对节点的引用。
错误? 任何 错误消息。如果节点在指定的超时时间内无法与智能手机通信,则存在。

SensorType

描述
ACCELEROMETER 表示加速度传感器。
GYROSCOPE 表示陀螺仪传感器。
MAGNETOMETER 表示磁力计传感器。
HEART_RATE 表示心率传感器。
LOCATION 表示GPS传感器。

CollectorManager

方法 返回类型 描述
isEnabled(sensor: SensorType) boolean 如果传感器类型在初始配置中启用,则返回true。
isReady(node: Node, sensor: SensorType) Promise<boolean> 如果传感器准备好收集数据,则返回true。
prepare(node: Node, sensor: SensorType) Promise 如果在准备过程中发生错误(例如,传感器不可用、没有权限等),则返回PrepareError。如果准备成功,则返回undefined
startCollecting(node: Node, sensor: SensorType, config?: CollectionConfiguration) Promise<void> 使用指定的配置在节点中开始传感器的数据收集。
stopCollecting(node: Node, sensor: SensorType) Promise<void> 停止节点中传感器的数据收集。
addSensorListener(listener: SensorListener, filters?: ListenerFilter) 数字 添加具有指定筛选器的监听器并返回监听器标识符。
removeSensorListener(listenerId?: number) void 删除由listenerId指定的监听器。如果没有提供,则删除所有监听器。

PrepareError

属性 类型 描述
节点 Node 引用产生PrepareError的节点。
message 字符串 描述错误的消息。

CollectionConfiguration

属性 类型 描述
sensorInterval SensorInterval 连续样本之间的时间。可以是NativeSensorInterval或毫秒值。
batchSize 数字 每个记录中要发送的样本数量。

SensorListener

(sensorRecord: SensorRecord) => void

ListenerFilter

属性 类型 描述
nodes? Node[] 相关监听器应用于哪些节点。
sensors? SensorType[] 相关监听器应用于哪些传感器。

[!TIP] 过滤器的工作方式如下

{ 
nodes: [node1, /* OR */ node2]
// AND
sensors: [SensorType.ACCELEROMETER, /* OR */ SensorType.GYROSCOPE]
}

SensorRecord

属性 类型 描述
type SensorType 收集数据的类型。
deviceId 字符串 收集数据的设备ID。
samples T[] 样本列表,其中T是TriAxialSensorSampleHeartRateSensorSampleLocationSensorSample

TriAxialSensorSample

属性 类型 描述
x 数字 组件 x
y 数字 组件 y
z 数字 组件 z

HeartRateSensorSample

属性 类型 描述
value 数字 心率值。

LocationSensorSample

属性 类型 描述
latitude 数字 纬度坐标分量。
longitude 数字 经度坐标分量。
altitude 数字 高度坐标分量。
verticalAccuracy 数字 纬度的估计误差。
horizontalAccuracy 数字 经度的估计误差。
speed 数字 当获取位置时的设备估计速度。
direction 数字 当获取位置时的设备估计方向。

PlainMessageClient

函数 返回类型 描述
enabled() boolean 如果初始配置中启用了普通消息功能,则返回true。
registerListener(listener: PlainMessageListener) void 为功能注册监听器。
unregisterListener() void 注销功能的监听器。
send(node: Node, plainMessage: PlainMessage) Promise<void> 向指定的节点发送消息。
sendExpectingResponse(node: Node, plainMessage: PlainMessage, timeout?: number) Promise 向指定的节点发送消息,并等待 timeout 毫秒以获取响应。

普通消息

属性 类型 描述
message 字符串 消息内容。
响应于? 普通消息 包含当前消息所响应的消息。 undefined 表示消息不是响应其他消息。

接收到的消息

属性 类型 描述
发送者节点ID 字符串 发送消息的节点的ID。
普通消息 普通消息 接收到的消息。

普通消息监听器

(receivedMessage: 接收到的消息) => void

许可证

Apache许可证2.0

LICENSE

作者

Miguel Matey Sanz

致谢

本库的开发得益于西班牙大学部(资助FPU19/05352)。