基于OpenHarmony3.0LTS和HarmonyOS2.0手机的温湿度计案例Demo

系统 OpenHarmony
本篇带给大家基于OpenHarmony3.0LTS和HarmonyOS2.0手机的温湿度计案例Demo。

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

一、概述

南向:基于OpenHarmony-v3.0-LTS 在润和智能家居套件上实现。

(1)自动连接到用鸿蒙手机创建的热点,指定热点名称OHOS、加密类型WPA2-Personal、密*码1234567890。

(2)进行温湿度燃气检测,在OLED上显示,将数据通过UDP发送到手机端(192.168.43.1)。

北向: 开发鸿蒙手机应用监听UDP数据,并显示温湿度数据,。

目前不足:

(1)Wifi 配网目前是代码里面写死的,碰一碰没有上。

(2)UDP 接收端IP也是写死的。

作为简单Demo分享,如果想要比较完善的案例可以参考​​数字管家​​上的案例。

二、南向Openharmony部分

主要代码结构如下图,完整代码见附件thermostat.zip。

1、 南向设备端温湿度的读取显示

(1) 南向设备端开启I2C配置

温湿度传感器AHT20、OLED显示需要用到I2C功能所以需要开启。

device\hisilicon\hispark_pegasus\sdk_liteos\build\config\usr_config.mk。

CONFIG_I2C_SUPPORT=y

(2) 南向设备端AHT20驱动修改

Code base用润和官方​​aht20.c ​​​和​​​​aht20.h ​​​​Openharmony1.0的驱动修改而来,主要修改如下,修改后的完整驱动见附件:

头文件和define修改如下:

#include "wifiiot_i2c.h"
#include "wifiiot_errno.h"
#define AHT20_I2C_IDX WIFI_IOT_I2C_IDX_0

改为:

#include "hi_i2c.h"
#define AHT20_I2C_IDX 0

并添加以下define和struct:

/**
* @brief Defines a module-level return value to indicate a successful operation.
*
*/
#define WIFI_IOT_SUCCESS 0
/**
* @brief Defines a module-level return value to indicate an operation failure.
*
*/
#define WIFI_IOT_FAILURE (-1)
// unsigned int I2cSetBaudrate(WifiIotI2cIdx id, unsigned int baudrate);
typedef struct {
/** Pointer to the buffer storing data to send */
unsigned char *sendBuf;
/** Length of data to send */
unsigned int sendLen;
/** Pointer to the buffer for storing data to receive */
unsigned char *receiveBuf;
/** Length of data received */
unsigned int receiveLen;
} IotI2cData;

修改AHT20_Read和AHT20_Write如下:

static uint32_t AHT20_Read(uint8_t* buffer, uint32_t buffLen)
{
WifiIotI2cData data = { 0 };
data.receiveBuf = buffer;
data.receiveLen = buffLen;
uint32_t retval = I2cRead(AHT20_I2C_IDX, AHT20_READ_ADDR, &data);
if (retval != WIFI_IOT_SUCCESS) {
printf("I2cRead() failed, %0X!\n", retval);
return retval;
}
return WIFI_IOT_SUCCESS;
}
static uint32_t AHT20_Write(uint8_t* buffer, uint32_t buffLen)
{
WifiIotI2cData data = { 0 };
data.sendBuf = buffer;
data.sendLen = buffLen;
uint32_t retval = I2cWrite(AHT20_I2C_IDX, AHT20_WRITE_ADDR, &data);
if (retval != WIFI_IOT_SUCCESS) {
printf("I2cWrite(%02X) failed, %0X!\n", buffer[0], retval);
return retval;
}
return WIFI_IOT_SUCCESS;
}

改为:

static uint32_t AHT20_Read(uint8_t* buffer, uint32_t buffLen)
{
IotI2cData data = { 0 };
data.receiveBuf = buffer;
data.receiveLen = buffLen;
uint32_t retval = IoTI2cRead(AHT20_I2C_IDX, AHT20_READ_ADDR, data.receiveBuf, data.receiveLen);
if (retval != WIFI_IOT_SUCCESS) {
printf("I2cRead() failed, %0X!\n", retval);
return retval;
}
return WIFI_IOT_SUCCESS;
}
static uint32_t AHT20_Write(uint8_t* buffer, uint32_t buffLen)
{
IotI2cData data = { 0 };
data.sendBuf = buffer;
data.sendLen = buffLen;
uint32_t retval = IoTI2cWrite(AHT20_I2C_IDX, AHT20_WRITE_ADDR, data.sendBuf, data.sendLen);
if (retval != WIFI_IOT_SUCCESS) {
printf("I2cWrite(%02X) failed, %0X!\n", buffer[0], retval);
return retval;
}
return WIFI_IOT_SUCCESS;
}

(3) 南向设备端OLED 显示驱动修改

见附件的oled.c、oled.h和oledfont.h,忘记哪里来的code base了,openharmony3.0与openharmony1.0的版本的差异仍然是I2C的API,主要差异如下:

#include "wifiiot_i2c.h"
u8 g_send_data[2] = { 0 };
u32 my_i2c_write(WifiIotI2cIdx id, u16 device_addr, u32 send_len)
{
u32 status;
WifiIotI2cData es8311_i2c_data = { 0 };
es8311_i2c_data.sendBuf = g_send_data;
es8311_i2c_data.sendLen = send_len;
status = I2cWrite(id, device_addr, &es8311_i2c_data);
if (status != 0) {
printf("===== Error: I2C write status = 0x%x! =====\r\n", status);
return status;
}
return 0;
}:
/**********************************************
// IIC Write Command
**********************************************/
void Write_IIC_Command(u8 IIC_Command)
{
g_send_data[0] = 0x00;
g_send_data[1] = IIC_Command;

my_i2c_write(WIFI_IOT_I2C_IDX_0, 0x78, 2);
}
/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(u8 IIC_Data)
{
g_send_data[0] = 0x40;
g_send_data[1] = IIC_Data;
my_i2c_write(WIFI_IOT_I2C_IDX_0, 0x78, 2);
}

Openharmony3.0:

#include "iot_i2c.h"
#define OLED_I2C_IDX 0
#define OLED_I2C_ADDR 0x78 // 默认地址为 0x78
#define OLED_I2C_CMD 0x00 // 0000 0000 写命令
#define OLED_I2C_DATA 0x40 // 0100 0000(0x40) 写数据
// unsigned int I2cSetBaudrate(WifiIotI2cIdx id, unsigned int baudrate);
typedef struct {
/** Pointer to the buffer storing data to send */
unsigned char *sendBuf;
/** Length of data to send */
unsigned int sendLen;
/** Pointer to the buffer for storing data to receive */
unsigned char *receiveBuf;
/** Length of data received */
unsigned int receiveLen;
} IotI2cData;
static uint32_t I2cWiteByte(uint8_t regAddr, uint8_t byte)
{
unsigned int id = OLED_I2C_IDX;
uint8_t buffer[] = {regAddr, byte};
IotI2cData i2cData = {0};
i2cData.sendBuf = buffer;
i2cData.sendLen = sizeof(buffer)/sizeof(buffer[0]);
return IoTI2cWrite(id, OLED_I2C_ADDR, i2cData.sendBuf, i2cData.sendLen);
}
/**********************************************
// IIC Write Command
**********************************************/
void Write_IIC_Command(u8 IIC_Command)
{
I2cWiteByte(OLED_I2C_CMD, IIC_Command);
}
/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(u8 IIC_Data)
{
I2cWiteByte(OLED_I2C_DATA, IIC_Data);
}

2、 南向设备端WIFI连接及UDP通讯的建立

可以参考之前的帖子#​​开发板漂流计划#小车控制由简入繁之UDP控制​​。

(1) 南向设备端WIFI 连接的建立

wifi连接的代码仍然使用了润和Gitee中的​​wifi_connecter.c​​​和​​wifi_connecter.h​​。

在thermostat.c调用主要代码如下,如需更改wifi账号和密*码只需修改WIFI_SSID和WIFI_PWD。

#include "wifi_connecter.h"
...
#define WIFI_SSID "OHOS"//手机开启的热点名称
#define WIFI_PWD "1234567890"//手机开启热点的密*码
#define WIFI_HOST_IP "192.168.43.1"//手机开启热点后默认的IP
...
static void Thermostat_DemoTask(void *arg)
{
...
// setup your AP params
WifiDeviceConfig apConfig = {0};
strcpy(apConfig.ssid, WIFI_SSID);
strcpy(apConfig.preSharedKey, WIFI_PWD);
apConfig.securityType = WIFI_SEC_TYPE_PSK;
int netId = ConnectToHotspot(&apConfig);//配网开始会阻塞等待直到联网成功
...
}

(2) 南向设备端UDP Server 温度检测和数据组合发送

主要代码在applications\sample\wifi-iot\app\thermostat\src\thermostat.c中,相关代码如下,进行温湿度和燃气检测,然后组合成字符串“temp: 24.83, humi: 31.00, gas: 0.54”发送

#include "lwip/sockets.h"
#define WIFI_HOST_IP "192.168.43.1"//手机开启热点后默认的IP
static float ConvertToVoltage(unsigned short data)
{
return (float)data * 1.8 * 4 / 4096;
}
void UdpServer(unsigned short port)
{
ssize_t retval = 0;
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // UDP socket
float humidity = 0.0f;
float temperature = 0.0f;
float gasSensorResistance = 0.0f;
static char line[32] = {0};
static char sendmessage[128] = "";
unsigned short data = 0;
struct sockaddr_in clientAddr = {0};
clientAddr.sin_family = AF_INET;
clientAddr.sin_port = htons(port); // 端口号,从主机字节序转为网络字节序
if (inet_pton(AF_INET, WIFI_HOST_IP, &clientAddr.sin_addr) <= 0) { // 将主机IP地址从“点分十进制”字符串 转化为 标准格式(32位整数)
printf("inet_pton failed!\r\n");
goto do_cleanup;
}
socklen_t clientAddrLen = sizeof(clientAddr);
struct sockaddr_in serverAddr = {0};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
if (retval < 0) {
printf("bind failed, %ld!\r\n", retval);
goto do_cleanup;
}
printf("bind to port %d success!\r\n", port);
//初始化AHT20
while (0 != AHT20_Calibrate()) {
printf("AHT20 sensor init failed!\r\n");
sleep(1);
OLED_Clear();
OLED_ShowString(0,16,"AHT20 Init Fail",16);
OLED_Refresh();
}
while(1)
{
// 发送 触发测量 命令,开始测量
retval = AHT20_StartMeasure();
if (retval != 0) {
printf("trigger measure failed!\r\n");
}
// 接收测量结果,拼接转换为标准值
retval = AHT20_GetMeasureResult(&temperature, &humidity);
if (retval != 0) {
printf("get humidity data failed!\r\n");
}
//读取燃气传感器ADC值
if (hi_adc_read(HI_ADC_CHANNEL_2, &data, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0)
== 0) {
float Vx = ConvertToVoltage(data);
// Vcc ADC GND
// | ______ | ______ |
// +---| MG-2 |---+---| 1kom |---+
// ------ ------
// 查阅原理图,ADC 引脚位于 1K 电阻和燃气传感器之间,燃气传感器另一端接在 5V 电源正极上
// 串联电路电压和阻止成正比:
// Vx / 5 == 1kom / (1kom + Rx)
// => Rx + 1 == 5/Vx
// => Rx = 5/Vx - 1
gasSensorResistance = 5 / Vx - 1;
}
//将信息显示到OLED上
OLED_ShowString(0, 0, "UDP Port:62021", 16);
snprintf(line, sizeof(line), "temp: %.2f", temperature);
OLED_ShowString(0, 16, line, 16);
snprintf(line, sizeof(line), "humi: %.2f", humidity);
OLED_ShowString(0, 32, line, 16);
snprintf(line, sizeof(line), "gas: %.2f kom", gasSensorResistance);
OLED_ShowString(0, 48, line, 16);
OLED_Refresh();
sleep(1);
//组合要发送的字符数据
snprintf(sendmessage, sizeof(sendmessage), "temp: %.2f, humi: %.2f, gas: %.2f", temperature, humidity, gasSensorResistance);
//通过UDP发送数据
retval = sendto(sockfd, sendmessage, strlen(sendmessage), 0, (struct sockaddr *)&clientAddr, sizeof(clientAddr));
}
do_cleanup:
printf("do_cleanup...\r\n");
close(sockfd);
}
static void Thermostat_DemoTask(void *arg)
{
...
UdpServer(62021);//启动 UDP 服务,端口62021
...
}

三、北向HarmonyOS 2.0部分

代码结构如下:

关键代码见附件src.zip。

1、 北向手机端 UI部分

只是做文本显示布局截图如下:

DemoApp\entry\src\main\js\default\pages\index\index.hml 内容如下:

<div class="container">
<text class="text">
{{ $t('strings.temp') }} {{ temp }}
</text>
<text class="text">
{{ $t('strings.humi') }} {{ humi }} %RH
</text>
<text class="text">
{{ $t('strings.gas') }} {{ gas }}
</text>
</div>

2、北向手机端添加网络权限

需要在DemoApp\entry\src\main\config.json中增加网络权限ohos.permission.INTERNET这样才能监听UDP数据。

  "module": {
...
"reqPermissions": [
{
"name": "ohos.permission.INTERNET"
}
],
...

3、北向手机端UDP 消息的监听

完整代码在\DemoApp\entry\src\main\java\com\soon\demoapp\UpdateDataServiceAbility.java下,关键代码截取如下:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
@Override
protected void onStart(Intent intent) {
HiLog.info(LABEL, "DemoApp onStart");
UpdateDataServiceAbility.GetStatusInfo getstatusinfo = new UpdateDataServiceAbility.GetStatusInfo();
Thread t = new Thread(getstatusinfo, "getstatusinfoThread");
t.start();
HiLog.info(LABEL, "线程开始执行--> " + t.isAlive());//判断是否启动
super.onStart(intent);
}
class GetStatusInfo implements Runnable {
@Override
public void run() {
try {
//监听端口设为 62021
server_sock = new DatagramSocket(62021);
recv_buffer = new byte[1024];//接收缓冲区,byte型
pac = new DatagramPacket(recv_buffer, recv_buffer.length);//构造一个packet
recv_string = "";
HiLog.info(LABEL, "开始等待消息 ");
while (true)//循环接受数据
{
server_sock.receive(pac);//阻塞式接收数据
//将byte[]转化成string
recv_string = new String(recv_buffer, 0, pac.getLength());
HiLog.info(LABEL, "接受到UDP数据:" + recv_string + "长度:" + recv_string.length());
if(recv_string.length() >= 35) {
/*
System.out.println("Soon 0~4:" + recv_string.substring(0, 4));
System.out.println("Soon 6~11:" + recv_string.substring(6, 11));

System.out.println("Soon 13~17:" + recv_string.substring(13, 17));
System.out.println("Soon 19~24:" + recv_string.substring(19, 24));

System.out.println("Soon 26~29:" + recv_string.substring(26, 29));
System.out.println("Soon 31~35:" + recv_string.substring(31, 35));
*/
if (recv_string.substring(0, 4).equals("temp")
&&recv_string.substring(13,17).equals("humi")
&&recv_string.substring(26,29).equals("gas")) {
tempValue = recv_string.substring(6, 11);
humiValue = recv_string.substring(19, 24);
gasValue = recv_string.substring(31, 35);
HiLog.info(LABEL, "tempValue:" + tempValue);
HiLog.info(LABEL, "humiValue:" + humiValue);
HiLog.info(LABEL, "gasValue:" + gasValue);
try {
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withAction(COMMON_UDP_INFO_CHANGED)//自定义字符串类型的action
.build();
intent.setOperation(operation);
intent.setParam("result","commonEventData");
intent.setParam("isCommonEvent",true);
CommonEventData eventData = new CommonEventData(intent);
CommonEventManager.publishCommonEvent(eventData);
HiLog.info(LABEL, "PublishCommonEvent SUCCESS");
} catch (RemoteException e) {
HiLog.info(LABEL, "Exception occurred during publishCommonEvent invocation.");
}
}
}

}

} catch (Exception e) {
e.printStackTrace();
}
}
}

在收到数据更新的时候会发一个公共消息COMMON_UDP_INFO_CHANGED通知数据更新,不知道是否有其他更好的方式:

                            try {
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withAction(COMMON_UDP_INFO_CHANGED)//自定义字符串类型的action
.build();
intent.setOperation(operation);
intent.setParam("result","commonEventData");
intent.setParam("isCommonEvent",true);
CommonEventData eventData = new CommonEventData(intent);
CommonEventManager.publishCommonEvent(eventData);
HiLog.info(LABEL, "PublishCommonEvent SUCCESS");
} catch (RemoteException e) {
HiLog.info(LABEL, "Exception occurred during publishCommonEvent invocation.");
}

4、 北向手机端JSFA 调用PA的实现

详细的讲解可以论坛上搜索有很多JSFA 调用PA的介绍,这里我是用的是Ability调用方式,接口调用试用同步方式。

(1)北向手机端JS FA端代码

DemoApp\entry\src\main\js\default\pages\index\index.js完整代码如下:

// 定义常量 0-Ability、1-Internal Ability
const ABILITY_TYPE_EXTERNAL = 0;//Ability调用方式
const ABILITY_TYPE_INTERNAL = 1;//Internal Ability调用方式
// 接口调用同步或者异步
const ACTION_SYNC = 0;//同步方式
const ACTION_ASYNC = 1;//异步方式
// 业务码
const ACTION_MESSAGE_UDP_UPDATE = 1001;// 主动更新
const ACTION_MESSAGE_UDP_SUBSCRIBE = 1002;// 订阅Subscribe
const ACTION_MESSAGE_UDP_UNSUBSCRIBE = 1003;// 取消订阅Unsubscribe
const SUCCESS = 0;
var timer = null;

export default {
data: {
temp : "",
humi : "",
gas : ""
},
environmentStatus: function () {
this.getEnvironmentStatus();
},
environmentStatusSubscribe: function () {
this.startEnvironmentStatusSubscribe();
},
environmentStatusUnSubscribe: function () {
this.startEnvironmentStatusUnSubscribe();
},
initAction: function (code) {
var actionData = {};
var action = {};
action.bundleName = "com.soon.demoapp";
action.abilityName = "com.soon.demoapp.UpdateDataServiceAbility";
action.messageCode = code;
action.data = actionData;
action.abilityType = ABILITY_TYPE_EXTERNAL;
action.syncOption = ACTION_SYNC;
return action;
},
onInit() {
console.info('Demo App onInit')
this.environmentStatusSubscribe();
},
onShow(){
console.info('Demo App onShow')
},
onActive(){
console.info('Demo App onActive')
},
onDestroy(){
console.info('Demo App onDestroy')
this.environmentStatusUnSubscribe();
},
getEnvironmentStatus: async function() {
var action = this.initAction(ACTION_MESSAGE_UDP_UPDATE); //给封装好的初始化函数传递操作码,确定要调用的业务
var result = await FeatureAbility.callAbility(action);
var ret = JSON.parse(result);
if (ret.code == SUCCESS) {
this.temp = ret.temp;
this.humi = ret.humi;
this.gas = ret.gas;
console.info('getEnvironmentStatus temp is:' + JSON.stringify(ret.temp)
+ ' humi is:' + JSON.stringify(ret.humi)
+ ' gas is:' + JSON.stringify(ret.gas));
} else {
this.temp = "NA";
this.humi = "NA";
this.gas = "NA";
console.error('getEnvironmentStatus error code:' + JSON.stringify(ret.code));
}
},
startEnvironmentStatusSubscribe: async function () {
try {
var action = this.initAction(ACTION_MESSAGE_UDP_SUBSCRIBE); //给封装好的初始化函数传递操作码,确定要调用的业务
var that = this;//that没改变之前仍然是指向当时的this,这样就不会出现找不到原来的对象
var result = await FeatureAbility.subscribeAbilityEvent(action,function (requestEnvironmentStatus) { //调用订阅服务API
var envInfo = JSON.parse(requestEnvironmentStatus).data; //将Json字符串转换为对象,并获取接口返回数据
that.temp = envInfo.temp;
that.humi = envInfo.humi;
that.gas = envInfo.gas;
console.info('startEnvironmentStatusSubscribe temp is:' + JSON.stringify(that.temp)
+ ' humi is:' + JSON.stringify(that.humi)
+ ' gas is:' + JSON.stringify(that.gas));
});
console.info(" startEnvironmentStatusSubscribe result = " + result);
} catch (pluginError) {
console.error("startEnvironmentStatusSubscribe error : result= " + result + JSON.stringify(pluginError));
}
},
startEnvironmentStatusUnSubscribe: async function () {
try {
var action = this.initAction(ACTION_MESSAGE_UDP_UNSUBSCRIBE);
var result = await FeatureAbility.unsubscribeAbilityEvent(action);
FeatureAbility.callAbility(action);
} catch (pluginError) {
console.error("startEnvironmentStatusUnSubscribe error : " + JSON.stringify(pluginError));
}
}
}:

用ACTION_MESSAGE_UDP_UPDATE的方式需要在JS 里面设置定时器一直去刷新。

如果用ACTION_MESSAGE_UDP_SUBSCRIBE和ACTION_MESSAGE_UDP_UNSUBSCRIBE的方式则不需要手动更细在PA有变化之后会通知更新。

另外在实现的时候有遇到用以下写法UI一直没有刷新的问题。

   var result = await FeatureAbility.subscribeAbilityEvent(action,function (requestEnvironmentStatus) { //调用订阅服务API
var envInfo = JSON.parse(requestEnvironmentStatus).data; //将Json字符串转换为对象,并获取接口返回数据
this.temp = envInfo.temp;
this.humi = envInfo.humi;
this.gas = envInfo.gas;
console.info('startEnvironmentStatusSubscribe temp is:' + JSON.stringify(this.temp)
+ ' humi is:' + JSON.stringify(this.humi)
+ ' gas is:' + JSON.stringify(this.gas));
});

后来才发现,需要将当下的this存到that,这样that没改变之前仍然是指向当时的this,这样就不会出现找不到原来的对象,导致无法更新了,最后改成下面写法解决问题。

var that = this;//that没改变之前仍然是指向当时的this,这样就不会出现找不到原来的对象
var result = await FeatureAbility.subscribeAbilityEvent(action,function (requestEnvironmentStatus) { //调用订阅服务API
var envInfo = JSON.parse(requestEnvironmentStatus).data; //将Json字符串转换为对象,并获取接口返回数据
that.temp = envInfo.temp;
that.humi = envInfo.humi;
that.gas = envInfo.gas;
console.info('startEnvironmentStatusSubscribe temp is:' + JSON.stringify(that.temp)
+ ' humi is:' + JSON.stringify(that.humi)
+ ' gas is:' + JSON.stringify(that.gas));
});

(2) 北向手机端PA端代码

主要代码在DemoApp\entry\src\main\java\com\soon\demoapp\UpdateDataServiceAbility.java中。

// ohos相关接口包
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.event.commonevent.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.rpc.*;
import ohos.utils.zson.ZSONObject;
import java.util.HashMap;
import java.util.Map;
public class UpdateDataServiceAbility extends Ability {
private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0, "Soon UpdateDataServiceAbility");
private MyRemote remote = new MyRemote();
private CommonEventSubscriber subscriber;
...
private String tempValue;
private String humiValue;
private String gasValue;
private static final int DEFAULT_TYPE = 0;
private static final String COMMON_UDP_INFO_CHANGED = "UDP_INFO_CHANGED";
@Override
protected void onStart(Intent intent) {
HiLog.info(LABEL, "DemoApp onStart");
UpdateDataServiceAbility.GetStatusInfo getstatusinfo = new UpdateDataServiceAbility.GetStatusInfo();
Thread t = new Thread(getstatusinfo, "getstatusinfoThread");
t.start();
HiLog.info(LABEL, "线程开始执行--> " + t.isAlive());//判断是否启动
super.onStart(intent);
}
// FA在请求PA服务时会调用Ability.connectAbility连接PA,连接成功后,需要在onConnect返回一个remote对象,供FA向PA发送消息
@Override
protected IRemoteObject onConnect(Intent intent) {
super.onConnect(intent);
return remote.asObject();
}
class MyRemote extends RemoteObject implements IRemoteBroker {
private static final int SUCCESS = 0;
private static final int ERROR = 1;
private static final int ACTION_MESSAGE_UDP_UPDATE = 1001;
private static final int ACTION_MESSAGE_UDP_SUBSCRIBE = 1002;
private static final int ACTION_MESSAGE_UDP_UNSUBSCRIBE = 1003;
MyRemote() {
super("MyService_MyRemote");
}
@Override
public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
switch (code) {
case ACTION_MESSAGE_UDP_UPDATE: {
reply.writeString(getEnvironmentInfo());
break;
}
case ACTION_MESSAGE_UDP_SUBSCRIBE: {
subscribeEvent(data, reply, option);
break;
}
case ACTION_MESSAGE_UDP_UNSUBSCRIBE: {
unSubscribeEnvironmentEvent(reply);
break;
}
default: {
Map<String, Object> result = new HashMap<String, Object>();
result.put("abilityError", ERROR);
reply.writeString(ZSONObject.toZSONString(result));
return false;
}
}
return true;
}
private void subscribeEvent(MessageParcel data, MessageParcel reply, MessageOption option) {
MatchingSkills matchingSkills = new MatchingSkills();
matchingSkills.addEvent(COMMON_UDP_INFO_CHANGED);
IRemoteObject notifier = data.readRemoteObject();
CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
subscriber = new CommonEventSubscriber(subscribeInfo) {
@Override
public void onReceiveEvent(CommonEventData commonEventData) {
replyMsg(notifier);
}
};
if (option.getFlags() == MessageOption.TF_SYNC) {
reply.writeString("subscribe common event success");
}
try {
CommonEventManager.subscribeCommonEvent(subscriber);
reply.writeString(" subscribe common event success");
} catch (RemoteException e) {
HiLog.info(LABEL, "%{public}s", "RemoteException in subscribeNotificationEvents!");
}
}
private void replyMsg(IRemoteObject notifier) {
MessageParcel notifyData = MessageParcel.obtain();
notifyData.writeString(getEnvironmentInfo());
try {
notifier.sendRequest(DEFAULT_TYPE, notifyData, MessageParcel.obtain(), new MessageOption());
} catch (RemoteException exception) {
HiLog.info(LABEL, "%{public}s", "replyMsg RemoteException !");
} finally {
notifyData.reclaim();
}
}
private String getEnvironmentInfo() {
// 返回结果当前仅支持String,对于复杂结构可以序列化为ZSON字符串上报
Map<String, Object> result = new HashMap<String, Object>();
result.put("code", SUCCESS);
result.put("temp", tempValue);
result.put("humi", humiValue);
result.put("gas", gasValue);
return ZSONObject.toZSONString(result);
}
private void unSubscribeEnvironmentEvent(MessageParcel reply) {
try {
CommonEventManager.unsubscribeCommonEvent(subscriber);
reply.writeString("Unsubscribe common event success!");
} catch (RemoteException | IllegalArgumentException exception) {
reply.writeString("Unsubscribe failed!");
HiLog.info(LABEL, "%{public}s", "Unsubscribe failed!");
}
subscriber = null;
}
@Override
public IRemoteObject asObject() {
return this;
}
}
...
}

在subscribeEvent 中会监听COMMON_UDP_INFO_CHANGED这个消息,收到这个消息后会通知更新。

以上本次分享内容,谢谢阅读!

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2023-04-24 15:11:51

系统开发鸿蒙

2020-10-30 09:31:16

2G

2023-04-17 16:21:58

操作系统鸿蒙

2023-03-22 09:23:53

I2C总线温度传感器

2023-03-03 13:45:00

数据中心传感器

2021-01-14 11:58:35

鸿蒙HarmonyOSHi3861

2020-11-27 11:52:40

OneNet

2020-11-26 12:02:07

OneNet平台

2020-12-14 13:51:43

HarmonyOS鸿蒙DevEco Stud

2021-05-06 11:40:54

MQTT物联网网关开发物联网

2020-12-16 12:30:18

华为鸿蒙HarmonyOS 2全场景

2023-02-28 15:49:09

鸿蒙应用开发

2020-12-21 09:57:52

OLED温湿度计hi3861

2020-12-21 17:55:02

华为HarmonyOS鸿蒙

2020-12-21 11:40:48

鸿蒙HarmonyOS2.回忆录

2012-11-20 16:26:58

手机银行

2021-10-14 15:48:28

鸿蒙HarmonyOS应用

2017-07-04 16:51:09

数据中心空调制冷

2021-03-25 18:00:53

HarmonyOS元服务开发者

2020-12-16 17:25:11

鸿蒙HarmonyOS操作系统
点赞
收藏

51CTO技术栈公众号