【IoT最佳实践】智慧烟感语音报警(代码篇)
本文承接【IoT最佳实践】智慧烟感语音报警(配置篇),为您解读智慧烟感语音报警DEMO的代码逻辑,助您开发自己的智慧烟感语音报警系统。
这个DEMO的业务逻辑如下:
指定端口启动服务器。
服务器向物联网平台订阅设备数据变化通知。
当数据被推送到指定端口时,分析数据,若数据满足条件则调用语音通话服务拨打用户电话。
大概了解了业务逻辑后,让我们来看具体的代码。
智慧烟感语音报警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并导入查看~
- 点赞
- 收藏
- 关注作者
评论(0)