- 版本:1.3.0
- GitHub: https://github.com/GeoTecINIT/nativescript-wearos-sensors
- NPM: https://npmjs.net.cn/package/nativescript-wearos-sensors
- 下载
- 昨天:0
- 上周:7
- 上个月:19
nativescript-wearos-sensors
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。
使用方法
该插件提供以下功能
- 从配对的智能手表收集传感器数据:可以从智能手机和智能手表启动/停止。智能手表可以通过 WearCommands 功能启动和停止数据收集。
- 纯文本消息:允许在两个设备之间发送和接收简单消息。
首先,您需要使用 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
获取连接的节点。一旦您获得连接的节点,您就必须遵循一些步骤来开始数据收集
- 检查节点上的特定传感器是否已准备好进行收集。
- 如果它没有准备好
- 这是因为传感器未在设备中。
- 传感器在设备中,但智能手表应用程序没有收集该传感器的权限。
- 如果我们缺乏权限,我们可以只是要求用户授予它们。
- 如果权限被拒绝,那就到此为止了...
- 如果权限被授予,我们可以开始收集!!
要开始数据收集,我们还应该指定一个 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
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是TriAxialSensorSample 、HeartRateSensorSample 或LocationSensorSample 。 |
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。
作者
致谢
本库的开发得益于西班牙大学部(资助FPU19/05352)。