共计 8982 个字符,预计需要花费 23 分钟才能阅读完成。
我的项目概述
可能有些同学曾经接触过了规范零碎上的软总线利用开发,然而你玩过轻量零碎上的软总线利用吗?当初它来了。咱们利用 OpenAtom OpenHarmony 3.1 Release(以下简称“OpenHarmony”)版本的轻量零碎软总线能力,将智能燃气检测设施和智能窗户通风设备组成一个轻量级分布式网络,实现设施之间的互相管制。
原理图如下:
当家中的燃气告警时,无需任何操作,间接管制窗户通风零碎中的电机工作。
开发阐明
从下面的视频中能够看到,相干案例设施的利用界面都能够分成外设交互页面和软总线操作页面两大块。在上面的零碎框图中能够看到相干页面和其依赖的相干轻量零碎能力。例如外设交互界面通过自定义 JSI 接口与设施硬件打交道,软总线操作界面则通过轻量零碎的设施治理能力、软总线能力来实现设施间的发现、认证、传输等软总线操作。
在上面的内容中咱们将以智能燃气告警器设施为例,将相干开发过程分成 JS 利用端开发、自定义 JSI 实现、开发板端代码三局部来阐明:
JS 利用开发
燃气告警器 JS 利用是基于 3.1 release 版本,并联合方舟开发框架(ArkUI)、分布式组网等个性,应用 JS 语言开发的一款分布式平安厨房利用。为了体现了 OpenHarmony 轻量级分布式个性,不仅须要思考页面该如何设计、利用怎么同外设交互,还须要思考两个轻量级设施间如何进行设施认证,设施间如何进行通信等问题。
所以在相干利用中设计了操作页面,报警页面以及设施认证页面。其中首页是设置燃气浓度阈值,以及显示以后燃气浓度;报警页面是当首页检测到以后燃气浓度达到或高于咱们设置的阈值时,会从首页跳转到报警界面;设施认证页面则是对两台设施进行分布式组网。
代码构造如下图:
外设交互页面开发
相干界面如上图所示,咱们将首页页面分成三个局部:顶部标签、燃气浓度显示、设置告警阈值。接下来是具体的解析内容:
1)顶部标签解析
顶部标签中除了相干文本界面,次要是顶部两个按钮,别离用来显示以后 Wi-Fi 连贯状态以及跳转到设施认证页面。
GetKey() {
com.get({ // 获取 wifi 状态
key: 'storage_key',
success: (data)=> {let res = JSON.parse(data)
if (res.wifi) {if(res.wifi == 'connected') {this.isWifi = true;} else {this.isWifi = false;}
}
.....
},
});
},
changePage(operation) {
router.replace({uri:"pages/dm/dm" // 跳转到设施认证页面});
}
2)燃气浓度显示
次要是获取以后燃气浓度,并实时刷新到相干界面上。
onInit() {setTimeout(()=>{setInterval(()=>this.GetKey(),500) // 每 500ms 获取一次
},3000);
},
GetKey() {
com.get({
key: 'storage_key',
success: (data)=> {let res = JSON.parse(data)
if (res.CurrentGasCONC) {
this.currentValue = res.CurrentGasCONC;
this.progressPercent = ((this.currentValue) /300) * 100
if(this.currentValue >this.PresetValue && !this.isChange){
this.isChange = true;
router.replace({uri:"pages/warn/warn" // 燃气数值超标后主动跳转告警页面});
}
}
},
......
});
},
3)设置报警阈值
首页界面中对于报警阈值的解决,次要蕴含减小预设阈值和增大预设阈值,都是通过调用相干 SetKey 操作实现的。
reduceProgress(){ // 减小预设阈值
if (this.PresetValue <= 0) {this.PresetValue = 0}else{this.PresetValue = parseInt(this.PresetValue) - 20
}
this.isChange = false;
this.setProgress = ((this.PresetValue) /300) * 100
this.SetKey('GasThreshold', this.PresetValue);
},
addProgress(){ // 增大预设阈值
if (this.PresetValue >= 300) {this.PresetValue = 300}else{this.PresetValue = parseInt(this.PresetValue) + 20
}
this.isChange = false;
this.setProgress = ((this.PresetValue) /300) * 100
this.SetKey('GasThreshold', this.PresetValue);
},
SetKey(key1, value1) {
com.set({
key: key1 + '',
value: value1 + '',
// success or failed 状态打印
});
},
设施认证页面开发
相干界面如上图所示,咱们将设施认证步骤分成四个步骤:发现设施、发动认证、容许认证、输出 PIN 码。接下来是具体的解析内容:
1)发现设施解析
设施认证因设施状态不同显示对应的 UI,上图显示的 UI 对应设施状态”status = start“。
startDevice(){this.subscribeId = Math.floor(Math.random() * 10000 + 1000)
var info = {
"subscribeId": this.subscribeId, // 特定随机的
"mode": 0xAA, // 设置被动发现模式,除此之外还有被动模式 DISCOVER_MODE_PASSIVE
"medium": 0, // 主动抉择发现介质,目前用的是 coap
"freq": 2, // 发送发现音讯的频率,目前用的是 HIGH 还有 LOW/MID/SUPER_HIGH
"isSameAccount": false, // 勾销同一账号下能力发现的限度
"isWakeRemote": false, // 目前轻量零碎没有睡眠模式,所以不必睡眠唤醒性能
"capability": 0 // 目前应用 DDMP
devicemanager.startDeviceDiscovery(info); // 开始设施发现
},
2)发动认证解析
AuthenticateDevice(){ // 发动认证
let extraInfo = {
targetPkgName: 'test',
appName: "Newname",
appDescription: "testAPP",
business: '0',
displayOwner: 0
};
let AuthParam = {
authType: 1, // 以 PIN 码形式进行认证校验
appIcon:null,
appThumbnail:null,
extraInfo: extraInfo
};
let _this = this;
devicemanager.authenticateDevice(this.statusInfo, AuthParam, {// 省略了相干 success 和 fail 回调解决,残缺代码见参考链接},
3)容许认证解析
当设施状态”status = join-pin“,容许相干认证动作并且显示相干 PIN 码。
joinAuthOk() {this.joinPin() // 切换显示 PIN 码界面
this.initStatue() // 获取 PIN 码并显示
devicemanager.setUserOperation(0)
},
initStatue() {this.log('initStatue')
const data = devicemanager.getAuthenticationParam()
// 参数值转换为 JSON 字符串写入 data
this.log('getAuthenticationParam:' + JSON.stringify(data))
// Authentication type, 1 for pin code.
// ode ==1,pin 码
if (data && data.authType == 1) {// 残缺代码见参考链接}
},
4)输出 PIN 码解析
当设施状态 ”status = main-pin”,进到相干 PIN 码输出、校验界面。
mainInputPin(s) { // 输出六位数字
if (this.pinNumb == 6) return
if (this.pinNumb < 6) {this.pin[this.pinNumb] = s
++this.pinNumb
}
if (this.pinNumb == 6) {console.log("verifyAuthInfo ok")
this.verifyAuthInfo(this.pin.join('')) // PIN 码校验
}
},
自定义 JSI 原理和实现
JSI 是 OpenHarmony 轻量和小型零碎的一种 JS API 实现机制,适宜封装 IO、CPU 密集型、OS 底层等能力给到 JS 利用调用,通过 JSI 能够实现 JS 与 C /C++ 代码相互拜访。与 OpenHarmony 轻量级零碎中波及到的 audio、device、sensor 等须要与硬件打交道的 JSI 模块相似,CommunicationKit 和 DeviceManager 模块同样首先要退出到相干的配置文件中。ace_lite_engine 通过 JSI::SetModuleAPI 将 JS 利用中应用的关键字映射成 C ++ 函数。具体操作如下:
foundation/ace/ace_engine_lite/frameworks/module_manager/ohos_module_config.h 中的 OHOS_MODULES 新增如下字段:
{"CommunicationKit", InitNativeApiCommunicationKit},
{"devicemanager", InitDeviceManagerModule},
加载自定义模块
如上所示,在 JS 利用外设管制界面中数据读取和命令下发时,引入了 CommunicationKit 模块,当初咱们就看一下相干具体内容:
InitNativeApiCommunicationKit 函数相干内容如下:
vendor/team_x/common/communicationkit/native_utils/src/nativeapi_communication_kit.cpp
void InitNativeApiCommunicationKit(JSIValue exports) {JSI::SetModuleAPI(exports, "get", NativeapiCommunicationKit::Get); // 与 JS 利用中的关键字统一
JSI::SetModuleAPI(exports, "set", NativeapiCommunicationKit::Set);
}
相干 C ++ 实现 NativeapiCommunicationKit::Get 和 Set 的形式相似,咱们参考轻量零碎源码中其余模块的实现,应用 ExecuteAsyncWork 函数。依据给定的参数创立一个异步工作,并将其分派给主应用程序工作处理程序。其获取燃气浓度逻辑在 ExecuteGet 实现,设置轻量零碎燃气告警阈值由 ExecuteSet 实现。函数 args 参数用来接管 JS 端传过来的参数(JSIValue 数组),argsNum 示意该数组长度。
ExecuteAsyncWork(thisVal, args, argsNum, ExecuteGet, false);
ExecuteAsyncWork(thisVal, args, argsNum, ExecuteSet, false);
加载设施治理模块
与自定义模块相似,JS 利用应用软总线接口时,须要在利用执行前加载设施治理模块。设施治理模块也是 OpenHarmony 零碎中的重要组成部分,咱们在规范零碎中是通过 NAPI 的形式来加载相干模块,而在咱们轻量零碎中,设施治理模块是通过 JSI 的形式来加载的。首先看到 InitDeviceManagerModule 函数相干内容如下:
foundation/distributedhardware/devicemanager/interfaces/kits/js_mini/src/native_devicemanager_js.cpp
void InitDeviceManagerModule(JSIValue exports) {JSI::SetModuleAPI(exports, "createDeviceManager", DeviceManagerModule::CreateDeviceManager);
......
JSI::SetModuleAPI(exports, "startDeviceDiscovery", DeviceManagerModule::StartDeviceDiscoverSync);
JSI::SetModuleAPI(exports, "stopDeviceDiscovery", DeviceManagerModule::StopDeviceDiscoverSync);
JSI::SetModuleAPI(exports, "authenticateDevice", DeviceManagerModule::AuthenticateDevice);
JSI::SetModuleAPI(exports, "verifyAuthInfo", DeviceManagerModule::VerifyAuthInfo);
JSI::SetModuleAPI(exports, "setUserOperation", DeviceManagerModule::SetUserOperationSync);
JSI::SetModuleAPI(exports, "getAuthenticationParam", DeviceManagerModule::GetAuthenticationParamSync);
......
}
开发板端代码开发阐明
如下图所示,咱们从轻量零碎软总线设施的系统启动流程登程,来剖析软总线利用执行的相干要点。第一步:首先初始化软总线 server;第二步:注册与软总线相干的服务,例如 PRC、设施治理 DeviceManager 服务;第三步:JS engine 加载 DeviceManager 接口申明;第四步:具体的 RPC 通信操作流程。
初始化软总线服务
轻量零碎设施启动的启动过程中,会注册相干初始化软总线服务线程。该线程中的次要内容就是调用 InitSoftBusServer 函数。该函数会初始化与软总线相干的配置、发现、认证等相干操作。
软总线相干服务注册
服务是 OpenHarmony 零碎中的一个重要概念,不同的功能模块,不同线程 / 过程之间的调用接口,都对立形象成了服务。利用服务机制,操作系统、驱动框架等提供的能力都能被包装成服务提供给到利用调用。上面给大家具体介绍软总线相干的服务注册细节和要点。
SAMGR:作为中介者,治理 Provider 提供的能力,同时帮忙 Consumer 发现 Provider 的能力。
Provider:服务的提供者,为零碎提供能力(对外接口)。
PRC 服务注册
RPC:(Remote Procedure Call) 用于跨设施跨过程间的通信,在轻量零碎软总线利用中,咱们利用 RPC 能力实现了平安厨房我的项目中两个设施的关联管制,RPC 服务注册的具体内容如下:
1. 创立相干的动态服务对象;
static MiniService g_miniService = {
.GetName = GetName, // 相干服务名为 mini_sa_rpc
.Initialize = Initialize,
.MessageHandle = MessageHandle,
.GetTaskConfig = GetTaskConfig,
SERVER_IPROXY_IMPL_BEGIN,
.Invoke = FeatureInvoke, // 对外提供 Invoke 办法,供 RPC 相干 client 端程序调用
IPROXY_END,
};
2. 注册相干的服务和缺省对象;
SAMGR_GetInstance()->RegisterService((Service *)&g_miniService);
SAMGR_GetInstance()->RegisterDefaultFeatureApi(MINI_SERVICE, GET_IUNKNOWN(g_miniService));
设施治理服务注册
如果没注册设施治理服务,那么相干软总线能力也就无从谈起。在轻量系统启动时,执行相干设施治理服务初始化动作,具体内容如下:
1)创立相干的动态服务对象;
static DeviceManagerSamgrService service = {
.GetName = GetName, // 相干服务名为 dev_mgr_svc
.Initialize = Initialize,
.MessageHandle = MessageHandle,
.GetTaskConfig = GetTaskConfig,
};
2)注册相干的服务和缺省对象;
SAMGR_GetInstance()->RegisterService((Service *)&service));SAMGR_GetInstance()->RegisterDefaultFeatureApi(DEVICE_MANAGER_SERVICE_NAME, GET_IUNKNOWN(service));
3)执行相干初始化动作。DeviceManager 服务的初始化函数将实现相干状态回调注册和传输通道初始化,而后执行相干 Publish 动作,做好接管发现音讯的筹备。
设施间 RPC 通信
在规范零碎利用开发中,咱们能够通过分布式数据库和启动近程 Ability 的形式实现设施之间的通信,而在轻量零碎中则通过 RPC 的办法来实现。在后面的内容中咱们讲了服务的概念,上面是拓展的相干原理图:
Consumer:服务的消费者,调用服务提供的性能(对外接口)。
在实现软总线组网后,如果检测到燃气度数超标后,按如下步骤即可实现对智能通风设备的管制:
1. 获取软总线网络中的相干节点信息;
GetAllNodeDeviceInfo("com.ohos.devicemanagerui", &nodeInfo, &infoNum);
2. 获取近程节点公布的 mini_sa_rpc 服务中对应的 IUnknown 办法;
IUnknown *miniDefApi = SAMGR_GetInstance()->GetRemoteDefaultFeatureApi(nodeInfo[0]->networkId, "mini_sa_rpc");
3. 查问服务所公布的相干能力,获取指向具体 API 接口的指针 miniInterface;
miniDefApi->QueryInterface(miniDefApi, 0, (void **) &miniInterface);
4. 调用相干 mini_sa_rpc 对外提供的 Invoke 能力;
miniInterface->Invoke(miniInterface, 1, &reply, NULL, NULL);
操作体验
- 提前准备好平安厨房场景中的智能窗户通风设备和智能燃气告警设施,并实现相干的编译和利用装置动作;
- 提前准备好失常工作的无线路由设施(请保障预设热点名称:test_wifi 明码:12345678;是否能连贯互联网均可)
- 将燃气检测设施和窗户通风设备上电,确认两个设施利用启动失常和操作失常;
- 按如下步骤将通风设备、燃气检测设施组成一个软总线网络:
● 别离点击两个设施利用界面右上角的软总线配置图标,进入软总线配置界面;
● 点击智能燃气检测设施利用发现图标,距离 3S 后点击发动认证图标;
● 点击智能通风设备软总线配置界面下的容许认证图标,失常状况下会显示一个 6 位数的 PIN 码;
● 点击智能燃气检测设施利用输出 PIN 码按钮,进入数字键盘输入 PIN 码;
● 别离点击两个利用软总线配置图标左上角的返回按键,进入设施管制界面。 -
设置燃气检测设施的阈值低于理论读取的燃气数值,燃气检测利用进入警报界面的同时会管制电机工作,主动通风换气,保障家居的平安。待到理论燃气数值低于设置的阈值时,则敞开电机。
参考链接
本我的项目中波及到的参考资料和相干文档门路如下:欧智通 BES2600WM 开发板疾速上手学习门路:
https://growing.openharmony.c…
轻量零碎利用开发软总线视频课程:
https://www.bilibili.com/vide…
设施治理模块文档:
https://gitee.com/openharmony…
智能燃气检测零碎样例:
https://growing.openharmony.c…
智能窗户通风零碎样例:
https://growing.openharmony.c…总结
从本文中能够看到与规范零碎一样利用都是调用设施治理模块提供的相干接口来实现的软总线发现、认证等性能,然而不同的中央在于规范零碎应用了预制的 DeviceManager_UI.hap 来显示 PIN 码、输出 PIN 码。而轻量零碎软总线利用中,相干 PIN 码显示、PIN 码输出须要本人调用相干接口。
与规范零碎软总线利用相比,目前轻量零碎软总线利用只实现了轻量零碎设施之前数据流转性能,轻量零碎分布式拉起、分布式数据库等性能待后续更新迭代。下一步还将钻研如何利用软总线来连贯轻量零碎和规范零碎,敬请大家期待。
丰盛多样的 OpenHarmony 开发样例离不开宽广合作伙伴和开发者的奉献,如果你也想把本人开发的样例分享进去,欢送提交到 OpenHarmony 常识体系 SIG 仓库。
共建开发样例参考 https://gitee.com/openharmony…