物联网架构成长之路(61)-物联网第三方应用命令下发方案
0.前言
上一篇博客讲的这个图,说到,设备主动上报数据到应用服务器端,只说到基于MQ来实现,只讲到安装篇,至于代码篇,等后面实际用到再继续深入了解。本篇博客主要讲,客户端(手机或者PC端)命令下发到设备,然后设备应答,返回结果到客户端。常用于扫码支付类应用。这该是如何设计呢?以前有说到,把手机或者PC客户端当作一个设备,同样接入MQTT Broker,这样,设备和客户端,同时订阅和发布相同Topic,就可以两者之间进行通信。这种方式实现比较简单。效率高。适用范围比较单一。一般也就用于自家设备与自家手机应用客户端。适合公司做自己项目的公司。因为这种方式,平台端还需要管理终端用户,这对于互联网公司来说,一般是不太乐意接受的。
下面讲到的这种异步调用与同步调用,比较适合一些硬件厂商,或者一些想做大平台的公司。就是提供API给第三方客户接入。完全分离设备端厂商与应用端厂商,两者只需要按照流程接入即可,不用管Topic的事情。这样做的好处是,可以做成一个类似小米一样的生态系统。定好协议,左边是给设备厂商接入,右边是给第三方公司,特别是互联网公司接入。平台只做好设备认证和客户应用接入。客户的终端客户我们平台端就不需要管了。专心做好平台,做好生态即可。
应用场景:
假如我是一个卖设备模块的公司,假如这个模块就一个开关功能。现在定义好模块的通信协议。开放给硬件产品公司模块,就一个功能,开跟关。至于硬件产品公司,把开关应用到消防安防的开关,还是闸门、门禁的开关,还是智能插座的开关等等开关类应用。然后这批模块,按照不同的产品公司,在物联网平台创建好模型,创建好产品。完成设备接入。
下一步,就是开放API给第三方软件公司。软件公司,只需要与平台对接,通过产品key,设备sn,命令参数,就可以下发命令到设备。第三方软件公司,开发自己的APP应用。接收命令后通过RPC调用物联网平台,平台下发命令,设备应答,平台返回命令下发结果。完成整个调用。(以上应用场景,均可用于共享仪器,扫码支付等场景)
1. 异步调用
2. 同步调用
注:本时序图,最后为什么会有轮询呢?因为在一个同步调用过程中,会设置超时,如果超时时间内,设备还无法回复。那么就返回超时并返回请求的Msgid给应用服务器。应用服务根据MsgID再去定时轮询。(也有可能是硬件故障无法回复)。
当然上面的应用服务器与客户端之间,除了Http请求外,可以采用其他的请求方式。
3. 同步调用参考代码
同步调用,是基于Java Servlet 3.x 提供的DeferredResult实现的。
MessageQueueDeferredService.java
1 package com.wunaozai.demo.deferred; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 import org.springframework.stereotype.Service; 7 import org.springframework.web.context.request.async.DeferredResult; 8 9 @Service 10 public class MessageQueueDeferredService { 11 12 /** 13 * 内存级别消息队列 14 */ 15 private final Map<String, DeferredResult<String>> results = 16 new HashMap<String, DeferredResult<String>>(); 17 18 /** 19 * 设置应答 20 * @param key 21 * @param value 22 * @return 23 */ 24 public boolean setResponse(String key, String value) { 25 if(results.containsKey(key)) { 26 DeferredResult<String> res = results.get(key); 27 res.setResult(value); 28 results.remove(key); 29 return true; 30 } 31 //可能超时或者不存在对应key 32 return false; 33 } 34 /** 35 * 设置请求 36 * @param key 37 * @param result 38 * @return 39 */ 40 public DeferredResult<String> setRequest(String key) { 41 DeferredResult<String> result = new DeferredResult<String>(5000L, "not response"); 42 results.put(key, result); 43 result.onTimeout(new Runnable() { 44 @Override 45 public void run() { 46 results.remove(key, result); 47 } 48 }); 49 result.onCompletion(new Runnable() { 50 @Override 51 public void run() { 52 results.remove(key, result); 53 } 54 }); 55 return result; 56 } 57 58 }
DeferredResultController.java
1 package com.wunaozai.demo.deferred; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.web.bind.annotation.GetMapping; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotation.RestController; 7 import org.springframework.web.context.request.async.DeferredResult; 8 9 @RestController 10 @RequestMapping(value="/deferredresult/") 11 public class DeferredResultController { 12 13 @Autowired 14 private MessageQueueDeferredService messagequeuedeferredService; 15 16 @GetMapping(value="/request") 17 public DeferredResult<String> setRequest(String msgid){ 18 DeferredResult<String> result = messagequeuedeferredService.setRequest(msgid); 19 return result; 20 } 21 @GetMapping(value="/response") 22 public boolean setResponse(String msgid, String value) { 23 boolean flag = messagequeuedeferredService.setResponse(msgid, value); 24 return flag; 25 } 26 27 }
运行结果
前三次请求,由于没有调用response方法,所以等到5秒超时。并返回not response。等第四次,在5秒内访问 http://127.0.0.1:8080/deferredresult/reponse?msgid=001&value=test ,然后就在 http://127.0.0.1:8080/deferredresult/request?msgid=003 页面看到返回结果test了。
参考资料:
https://www.cnblogs.com/coderxiaohei/p/14061468.html
本文地址:https://www.cnblogs.com/wunaozai/p/14078660.html
本系列目录: https://www.cnblogs.com/wunaozai/p/8067577.html
个人主页:https://www.wunaozai.com/
作者:无脑仔的小明 出处:http://www.cnblogs.com/wunaozai/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 如果文中有什么错误,欢迎指出。以免更多的人被误导。有需要沟通的,可以站内私信,文章留言,或者关注“无脑仔的小明”公众号私信我。一定尽力回答。 |