【IoT最佳实践】智慧烟感语音报警(代码篇)

举报
我是卤蛋 发表于 2020/01/21 15:58:25 2020/01/21
【摘要】 之前我们介绍了如何基于DEMO制作一个智慧烟感语音报警系统,本文为您从代码实现层面解读如智慧烟感语音报警系统的DEMO。

本文承接【IoT最佳实践】智慧烟感语音报警(配置篇),为您解读智慧烟感语音报警DEMO的代码逻辑,助您开发自己的智慧烟感语音报警系统。

这个DEMO的业务逻辑如下:

  1. 指定端口启动服务器。

  2. 服务器向物联网平台订阅设备数据变化通知。

  3. 当数据被推送到指定端口时,分析数据,若数据满足条件则调用语音通话服务拨打用户电话。

大概了解了业务逻辑后,让我们来看具体的代码。

1579592960945423.png

智慧烟感语音报警DEMO有两个包,com.iot_voice.demo包中是DEMO主要的业务逻辑代码,com.utils包中是一些工具类,大部分不用关注其具体实现,但Contants类除外,这个类里面定义了DEMO运行时要用到的各种常量,包括物联网平台对接信息,订阅推送地址,语音通知平台对接信息,号码信息,告警内容信息等,此处就不把代码贴出来了,请在实际使用时根据注释和实际情况具体调整。

该DEMO的main函数位于SubscribeServiceNotification类中,运行后首先就调用SimpleHttpServer类的startServer方法启动了一个服务器,指定端口号是8888:

// start server to receive message
SimpleHttpServer.startServer(8888);

SimpleHttpServer类中的相关方法如下:

public SimpleHttpServer(int port) throws IOException {
this.port = port;
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_MULTIPLE);
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().setReuseAddress(true);
serverSocketChannel.socket().bind(new InetSocketAddress(this.port));
}
public void service() {
while (true) {
SocketChannel socketChannel = null;
try {
socketChannel = serverSocketChannel.accept();
executorService.execute(new Handler(socketChannel));
} catch (IOException e) {
System.out.println(ExceptionUtil.getBriefExceptionStackTrace(e));
}
}
}
public static void startServer(final int port) {
System.out.println("Enabling the server..., Server port = " + port);
Thread t = new Thread(new Runnable() {
public void run() {
try {
new SimpleHttpServer(port).service();
} catch (Exception e) {
System.out.println("Failed to enable the server. Server port = " + port);
System.out.println(ExceptionUtil.getBriefExceptionStackTrace(e));
System.out.println();
}
}
});
t.start();
}

服务器启动后,再向物联网平台订阅设备数据变化通知(调用订阅接口前还要先调用鉴权接口获取accesstoken):

// Two-Way Authentication
HttpsUtil httpsUtil = new HttpsUtil();
httpsUtil.initSSLConfigForTwoWay();
// Authentication.get token
String accessToken = login(httpsUtil);
//Please make sure that the following parameter values have been modified in the Constant file.
String appId = Constant.IOT_APPID; 
String urlSubscribe = Constant.SUBSCRIBE_SERVICE_NOTIFYCATION; 
String callbackurl = Constant.IOT_CALLBACK_URL; 
//NA subscribe "deviceDataChanged" notification from the IoT platform      
Map<String, Object> paramServiceSubscribe = new HashMap<>();
paramServiceSubscribe.put("notifyType", "deviceDataChanged");
paramServiceSubscribe.put("callbackUrl", callbackurl);
String jsonRequest = JsonUtil.jsonObj2Sting(paramServiceSubscribe);
Map<String, String> header = new HashMap<>();
header.put(Constant.HEADER_APP_KEY, appId);
header.put(Constant.HEADER_APP_AUTH, "Bearer" + " " + accessToken);
HttpResponse httpResponse = httpsUtil.doPostJson(urlSubscribe, header, jsonRequest);
String bodySubscribe = httpsUtil.getHttpResponseBody(httpResponse);
System.out.println("SubscribeServiceNotification, notifyType:deviceDataChanged, callbackurl:" + callbackurl +", response content:");
System.out.print(httpResponse.getStatusLine());System.out.println(bodySubscribe);
System.out.println();

然后,服务器进入等待状态,等到物联网平台推送了一条设备消息上来后,首先从消息中取出JSON格式的消息体,并判断这条消息是否和上一条推送的消息一致,若一致,则不处理这条消息(避免重推的消息重复触发告警)。

ByteBuffer buffer = ByteBuffer.allocate(2048);
socketChannel.read(buffer);
buffer.flip();
recvString = new String(buffer.array());
String responseJsonBody = "";
if (recvString != null) {
try {
responseJsonBody = recvString.substring(recvString.lastIndexOf("\n")).trim();
} catch (Exception e) {
System.out.println("Get responseJsonBody fail.");
}
}
// 当推送消息与上一条消息相同时,抛弃当前消息
if (lastResponseJsonBody != null) {
if (lastResponseJsonBody.equals(responseJsonBody)){
return;
} 
}
lastResponseJsonBody = responseJsonBody;
System.out.print("Received the message pushed by the platform: ");
System.out.println(responseJsonBody);
System.out.println();
// TODO 向物联网平台返回200 OK,请自行实现

然后解析这个JSON消息体,获取关键信息(设备ID,烟雾浓度,温度):

// 分析推送消息,获取deviceId,smoke和temperature 
Integer smoke = null;
Integer temperature = null;
String deviceId = null;
try {
@SuppressWarnings("deprecation")
JsonObject message =  new JsonParser().parse(responseJsonBody).getAsJsonObject();
deviceId = message.get("deviceId").getAsString();
JsonObject service = message.get("service").getAsJsonObject();
if("Sensor".equals(service.get("serviceId").getAsString())) {
JsonObject data = service.get("data").getAsJsonObject();
smoke = data.get("smoke").getAsInt();
temperature = data.get("temperature").getAsInt();                
}
} catch (Exception e) {
System.out.println("Parse responseJsonBody fail.");
}

使用设备ID获取用户信息:

// TODO 产商安装烟雾报警器时需要记录设备ID、户主姓名、电话和安装地点的关联关系,此处根据deviceId获取户主的姓名、电话和设备安装地点。
// 此处仅为示例,实际应该从持久化数据库中读取
if (deviceId != null) {
Map<String, String> userInfoDetails = getUserIfinfo(deviceId);
String ownername = userInfoDetails.get("ownername");
String phonenumber = userInfoDetails.get("phonenumber");String location = userInfoDetails.get("location");

判断烟雾浓度和温度的值是否高于阈值,如果均高于阈值则触发告警:

// 烟雾浓度和温度均高于阈值时触发语音通知告警
if (smoke != null && temperature != null) {
if(smoke > Constant.SMOKE_THRESHOLD && temperature > Constant.TEMP_THRESHOLD) {
 // 构造playInfoList参数
List<Map<String, Object>> playInfoList = new ArrayList<Map<String, Object>>();
// 使用TTS模板作为放音内容
List<String> templateParas = new ArrayList<String>();
templateParas.add(ownername);
templateParas.add(location);
playInfoList.add(CallNotify.getplayInfo(Constant.TEMPLATEID, templateParas));
// 调用语音通知接口
try {
CallNotify.callNotifyAPI(Constant.BINDNUM, Constant.DSPNUM, phonenumber, playInfoList);
} catch (Exception e) {
System.out.println("Call user fail.");
}
}
}

触发语音通知则是通过调用CallNotify类的callNotifyAPI方法,这里就不展开细讲了。

至此,该DEMO的整体业务逻辑结束,若您对DEMO的具体代码感兴趣,请参考上一期下载DEMO并导入查看~


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。