一、概述
南向:基于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这个消息,收到这个消息后会通知更新。
以上本次分享内容,谢谢阅读!