设备端OTA升级的https实现

简介: OTA(Over-the-Air Technology)即空中下载技术。物联网平台支持通过OTA方式进行设备升级。

MQTT协议下OTA升级流程如下图所示:

1.jpg

在物联网平台控制台上,添加升级包、验证升级包并发起批量升级任务。具体操作,请参见推送升级包到设备端

下面是通过https下载升级包的过程:

package com.aliyun.alinkSdk; import com.alibaba.fastjson.JSONObject; import com.aliyun.alink.dm.api.DeviceInfo; import com.aliyun.alink.dm.api.InitResult; import com.aliyun.alink.linkkit.api.ILinkKitConnectListener; import com.aliyun.alink.linkkit.api.IoTMqttClientConfig; import com.aliyun.alink.linkkit.api.LinkKit; import com.aliyun.alink.linkkit.api.LinkKitInitParams; import com.aliyun.alink.linksdk.cmp.connect.channel.MqttPublishRequest; import com.aliyun.alink.linksdk.cmp.connect.channel.MqttSubscribeRequest; import com.aliyun.alink.linksdk.cmp.core.base.*; import com.aliyun.alink.linksdk.cmp.core.listener.*; import com.aliyun.alink.linksdk.tools.AError; import com.aliyun.alink.linksdk.tools.ALog; import org.apache.commons.codec.binary.Base64; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; public class OTA {  // ===================需要用户填写的参数,开始===========================  // 产品productKey,设备证书参数之一  private static String productKey = "xxx";  // 设备名字deviceName,设备证书参数之一  private static String deviceName = "xxx";  // 设备密钥deviceSecret,设备证书参数之一  private static String deviceSecret = "xxx";  // 设备密钥productSecret,设备证书参数之一  private static String productSecret = "";  private static boolean isLoginSuccess = false;  //OTA 升级  //设备上报固件升级信息  private static String topic = "/ota/device/inform/" + productKey + "/" + deviceName;  //固件升级信息下行  private static String subscribeTopic = "/ota/device/upgrade/" + productKey + "/" + deviceName;  //设备上报固件升级进度  private static String topic1 = "/ota/device/progress/" + productKey + "/" + deviceName;  //设备主动拉取固件升级信息  private static String topic2 = "/sys/" + productKey + "/" + deviceName + "/thing/ota/firmware/get";  private static String subscribeTopic2 = "/sys/" + productKey + "/" + deviceName + "/thing/ota/firmware/get_reply";  //设备主动拉取固件升级信息  private static String topic3 = "/sys/" + productKey + "/" + deviceName + "/thing/file/download";  private static String subscribeTopic3 = "/sys/" + productKey + "/" + deviceName + "/thing/file/download_reply";  private static String module = "default";  private String version = "1.0";  private String streamId = "";  private int streamFileId = 0;  private int fizeSize = 0;  private int curFileSize = 0;  private static OTA airC = new OTA();  // ===================需要用户填写的参数,结束===========================  public static void main(String[] args) throws InterruptedException, IOException {  ALog.setLevel(ALog.LEVEL_DEBUG);  //初始化  airC.init(productKey, deviceName, deviceSecret);  //下行数据监听  airC.registerNotifyListener();  while(true){  if(isLoginSuccess)  {  break;  }  Thread.sleep(100);  }  //消息订阅  airC.subscribe(subscribeTopic);  airC.subscribe(subscribeTopic2);  airC.subscribe(subscribeTopic3);  //ota升级,推送当前设备OTA模块版本号  String payload = "{\"id\":\"100\",\"params\":{\"version\":\""+airC.version+"\",\"module\":\""+module+"\"}}";  airC.publish(topic, false, payload);  payload = "{\"id\":\"100\",\"params\":{\"module\":\""+module+"\"},\"version\":\"1.0\",\"method\": \"thing.ota.firmware.get\"}";  airC.publish(topic2, false, payload);  }  /**  * 初始化  *  * @param pk productKey  * @param dn devcieName  * @param ds deviceSecret  * @throws InterruptedException  */  public void init(String pk, String dn, String ds) throws InterruptedException {  LinkKitInitParams params = new LinkKitInitParams();  // 设置 MQTT 初始化参数  IoTMqttClientConfig config = new IoTMqttClientConfig();  config.productKey = pk;  config.deviceName = dn;  config.deviceSecret = ds;  //config.channelHost = "xxx:1883";  config.channelHost = productKey+".iot-as-mqtt.cn-shanghai.aliyuncs.com:1883";  config.receiveOfflineMsg = true;  params.mqttClientConfig = config;  //MqttConfigure.setKeepAliveInterval(90);  // 设置初始化设备证书信息,用户传入  DeviceInfo deviceInfo = new DeviceInfo();  deviceInfo.productKey = pk;  deviceInfo.deviceName = dn;  deviceInfo.deviceSecret = ds;  params.deviceInfo = deviceInfo;  LinkKit.getInstance().init(params, new ILinkKitConnectListener() {  public void onError(AError aError) {  isLoginSuccess = false;  System.out.println("init failed !! code=" + aError.getCode() + ",msg=" + aError.getMsg() + ",subCode="  + aError.getSubCode() + ",subMsg=" + aError.getSubMsg());  }  public void onInitDone(InitResult initResult) {  System.out.println("init success !!");  isLoginSuccess = true;  }  });  }  /**  * 监听下行数据  */  public void registerNotifyListener() {  LinkKit.getInstance().registerOnNotifyListener(new IConnectNotifyListener() {  @Override  public boolean shouldHandle(String connectId, String topic) {  //处理所有Topic的消息  System.out.println("registerNotifyListener registerOnNotifyListener "+connectId);  System.out.println("registerNotifyListener registerOnNotifyListener "+topic);  return true;  }  @Override  public void onNotify(String connectId, String topic, AMessage aMessage) {  //打印一下Topic和message  System.out.println("registerNotifyListener onNotify connectId: " + connectId);  System.out.println("registerNotifyListener onNotify topic: " + topic);  System.out.println("registerNotifyListener onNotify message: " + new String((byte[]) aMessage.getData()));  if (topic.contains("/ota/device/upgrade/")) {  String content = new String((byte[]) aMessage.getData());  JSONObject request = JSONObject.parseObject(content);  System.out.println("content==="+content);  String dProtocol = "";  String url = "";  String code = request.getString("code");  JSONObject data = request.getJSONObject("data");  if(data.containsKey("dProtocol")){  dProtocol = data.getString("dProtocol");  }  if(data.containsKey("streamId")){  airC.streamId = data.getString("streamId");  }  if(data.containsKey("streamFileId")){  airC.streamFileId = data.getInteger("streamFileId");  }  if(data.containsKey("url")){  url = data.getString("url");  }  if(data.containsKey("version")){  airC.version = data.getString("version");  }  if(data.containsKey("size")){  airC.fizeSize = data.getInteger("size");  }  System.out.println("code==="+code);  System.out.println("dProtocol==="+dProtocol);  System.out.println("url==="+url);  if(code.equals("1000") && dProtocol == "mqtt"){  } else if(code.equals("1000") && !url.isEmpty()){  try {  airC.saveUrlFile(url,"D:\\2.zip");  topic = "/ota/device/progress/" + productKey + "/" + deviceName;  String payload = "{\"id\":\"100\",\"params\":{\"step\":\"100\",\"desc\":\"test\",\"module\":\""+module+"\"}}";  airC.publish(topic, false, payload);  topic = "/ota/device/inform/" + productKey + "/" + deviceName;  payload = "{\"id\":\"100\",\"params\":{\"version\":\""+airC.version+"\",\"module\":\""+module+"\"}}";  airC.publish(topic, false, payload);  } catch (Exception e) {  e.printStackTrace();  }  }  }else if (topic.contains("/ota/firmware/get_reply")) {  String content = new String((byte[]) aMessage.getData());  JSONObject request = JSONObject.parseObject(content);  System.out.println("content==="+content);  String dProtocol = "";  String url = "";  int code = request.getInteger("code");  JSONObject data = request.getJSONObject("data");  if(data.containsKey("dProtocol")){  dProtocol = data.getString("dProtocol");  }  if(data.containsKey("streamId")){  airC.streamId = data.getString("streamId");  }  if(data.containsKey("streamFileId")){  airC.streamFileId = data.getInteger("streamFileId");  }  if(data.containsKey("url")){  url = data.getString("url");  }  if(data.containsKey("version")){  airC.version = data.getString("version");  }  if(data.containsKey("size")){  airC.fizeSize = data.getInteger("size");  }  if(code == 200 && dProtocol == "mqtt"){  } else if(code == 200 && !url.isEmpty()){  try {  airC.saveUrlFile(url,"D:\\3.zip");  topic = "/ota/device/progress/" + productKey + "/" + deviceName;  String payload = "{\"id\":\"100\",\"params\":{\"step\":\"100\",\"desc\":\"test\",\"module\":\""+module+"\"}}";  airC.publish(topic, false, payload);  topic = "/ota/device/inform/" + productKey + "/" + deviceName;  payload = "{\"id\":\"100\",\"params\":{\"version\":\""+airC.version+"\",\"module\":\""+module+"\"}}";  airC.publish(topic, false, payload);  } catch (Exception e) {  e.printStackTrace();  }  }  }else if (topic.contains("/thing/file/download_reply")) {  }  }  @Override  public void onConnectStateChange(String connectId, ConnectState connectState) {  System.out.println("registerNotifyListener onConnectStateChange "+connectId);  System.out.println("registerNotifyListener onConnectStateChange "+connectState.toString());  if(connectState==ConnectState.DISCONNECTED)  {  try {  //LinkKit.getInstance().deinit();  Thread.sleep(10000);  OTA airC = new OTA();  airC.init(productKey, deviceName, deviceSecret);  } catch (InterruptedException e) {  e.printStackTrace();  }  }  }  });  }  /**  * 发布消息  *  * @param topic 发送消息的Topic  * @param payload 发送的消息内容  */  public void publish(String topic, boolean isRPC, String payload) {  MqttPublishRequest request = new MqttPublishRequest();  request.topic = topic;  request.payloadObj = payload;  //request.qos = 1;  //request.replyTopic = topic+"_reply";  //request.isRPC = isRPC;  System.out.println("publish start");  LinkKit.getInstance().getMqttClient().publish(request, new IConnectSendListener() {  @Override  public void onResponse(ARequest aRequest, AResponse aResponse) {  System.out.println("publish aRequest: " + (aRequest==null?"":aRequest.toString()));  System.out.println("publish onResponse: " + (aResponse==null?"":aResponse.data));  }  @Override  public void onFailure(ARequest aRequest, AError aError) {  System.out.println("publish onFailure: " + (aError==null?"":(aError.getCode()+aError.getMsg())));  }  });  System.out.println("publish end");  }  /**  * 发布消息  *  * @param topic 发送消息的Topic  * @param bytes 发送的消息内容  */  public void publishBytes(String topic, byte[] bytes) {  MqttPublishRequest request = new MqttPublishRequest();  request.topic = topic;  request.payloadObj = bytes;  //request.qos = 0;  //request.replyTopic = replyTopic;  //request.isRPC = false;  System.out.println("publishBytes start");  LinkKit.getInstance().getMqttClient().publish(request, new IConnectSendListener() {  @Override  public void onResponse(ARequest aRequest, AResponse aResponse) {  System.out.println("publishBytes onResponse: " + (aResponse==null?"":aResponse.data));  }  @Override  public void onFailure(ARequest aRequest, AError aError) {  System.out.println("publishBytes onFailure: " + (aError==null?"":(aError.getCode()+aError.getMsg())));  }  });  System.out.println("publishBytes end");  }  /**  * 订阅消息  *  * @param topic 订阅消息的Topic  */  public void subscribe(String topic) {  MqttSubscribeRequest request = new MqttSubscribeRequest();  request.topic = topic;  //是否订阅Topic,默认为true,如果设置为false,则不会订阅这个Topic  request.isSubscribe = true;  System.out.println("subscribe start");  LinkKit.getInstance().getMqttClient().subscribe(request, new IConnectSubscribeListener() {  @Override  public void onSuccess() {  System.out.println("subscribe onSuccess");  }  @Override  public void onFailure(AError aError) {  System.out.println("subscribe onFailure");  }  });  System.out.println("subscribe end");  }  /**  * 取消订阅消息  *  * @param topic 订阅消息的Topic  */  public void unsubscribe(String topic) {  MqttSubscribeRequest request = new MqttSubscribeRequest();  request.topic = topic;  //是否订阅Topic,默认为true,如果设置为false,则不会订阅这个Topic  request.isSubscribe = false;  System.out.println("unsubscribe start");  LinkKit.getInstance().getMqttClient().unsubscribe(request, new IConnectUnscribeListener() {  @Override  public void onSuccess() {  System.out.println("unsubscribe onSuccess");  }  @Override  public void onFailure(AError aError) {  System.out.println("unsubscribe onFailure");  }  });  System.out.println("unsubscribe end");  }  /**  * hex字符串转byte数组  * @param inHex 待转换的Hex字符串  * @return 转换后的byte数组结果  */  public static byte[] hexToByteArray(String inHex){  int hexlen = inHex.length();  byte[] result;  if (hexlen % 2 == 1){  //奇数  hexlen++;  result = new byte[(hexlen/2)];  inHex="0"+inHex;  }else {  //偶数  result = new byte[(hexlen/2)];  }  int j=0;  for (int i = 0; i < hexlen; i+=2){  result[j]=hexToByte(inHex.substring(i,i+2));  j++;  }  return result;  }  public static byte hexToByte(String inHex) {  return (byte) Integer.parseInt(inHex, 16);  }  /**  * 字节数组转16进制  * @param bytes 需要转换的byte数组  * @return 转换后的Hex字符串  */  public static String bytesToHex(byte[] bytes) {  StringBuffer sb = new StringBuffer();  for(int i = 0; i < bytes.length; i++) {  String hex = Integer.toHexString(bytes[i] & 0xFF);  if(hex.length() < 2){  sb.append(0);  }  sb.append(hex);  }  return sb.toString();  }  //需要使用2字节表示b  public static String numToHex16(int b) {  return String.format("%04x", b);  }  public static byte[] byteMergerAll(byte[]... values){  int length_byte=0;  for(int i=0; i<values.length; i++){  length_byte+=values[i].length;  }  byte[]all_byte = new byte[length_byte];  int countLength = 0;  for(int i=0; i<values.length; i++){  System.arraycopy(values[i],0, all_byte, countLength, values[i].length);  countLength += values[i].length;  }  return all_byte;  }  /*请求url获取返回的内容*/  public static String getReturn(HttpURLConnection connection) throws IOException {  StringBuffer buffer = new StringBuffer();  //将返回的输入流转换成字符串  try (InputStream inputStream = connection.getInputStream();  InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");  BufferedReader bufferedReader = new BufferedReader(inputStreamReader);) {  String str = null;  while ((str = bufferedReader.readLine()) != null) {  buffer.append(str);  }  String result = buffer.toString();  System.out.println("result" + result);  OTA airC = new OTA();  String topic = "/a1y4bqYyUTc/329391A46675430DE581A44248DF3A6B/user/upward";  String payload = "{\"title\":\"position\",\"data\":{\"longitude\":\"113.450761\",\"latitude\":\"23.103239\",\"altitude\":\"0.000000\",\"coordsys\":2,\"positionType\":4}}";  airC.publish(topic, false, payload);  return result;  }  }  public static String newStringByBase64(byte[] bytes) throws UnsupportedEncodingException {  if (bytes == null || bytes.length == 0) {  return null;  }  return new String(Base64.encodeBase64(bytes, false), "utf8");  }  public static byte[] getContent(String filePath) throws IOException {  File file = new File(filePath);  long fileSize = file.length();  if (fileSize > Integer.MAX_VALUE) {  System.out.println("file too big...");  return null;  }  FileInputStream fi = new FileInputStream(file);  byte[] buffer = new byte[(int) fileSize];  int offset = 0;  int numRead = 0;  while (offset < buffer.length  && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {  offset += numRead;  }  // 确保所有数据均被读取  if (offset != buffer.length) {  throw new IOException("Could not completely read file "  + file.getName());  }  fi.close();  return buffer;  }  //获取网络文件,转存到fileDes中,fileDes需要带文件后缀名  public static void saveUrlFile(String fileUrl,String fileDes) throws Exception  {  File toFile = new File(fileDes);  if (toFile.exists())  {  //throw new Exception("file exist");  return;  }  toFile.createNewFile();  FileOutputStream outImgStream = new FileOutputStream(toFile);  System.out.println(getUrlFileData(fileUrl));  outImgStream.write(getUrlFileData(fileUrl));  outImgStream.close();  }  //获取链接地址文件的byte数据  public static byte[] getUrlFileData(String fileUrl) throws Exception  {  URL url = new URL(fileUrl);  HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();  httpConn.connect();  InputStream cin = httpConn.getInputStream();  ByteArrayOutputStream outStream = new ByteArrayOutputStream();  byte[] buffer = new byte[1024];  int len = 0;  while ((len = cin.read(buffer)) != -1) {  outStream.write(buffer, 0, len);  }  cin.close();  byte[] fileData = outStream.toByteArray();  outStream.close();  return fileData;  } } 
相关实践学习
快速体验阿里云云消息队列RocketMQ版
本实验将带您快速体验使用云消息队列RocketMQ版Serverless系列实例进行获取接入点、创建Topic、创建订阅组、收发消息、查看消息轨迹和仪表盘。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
安全 JavaScript Java
记一次网站全站http升级为https的过程,websocket : ws升级为wss遇到的问题等
记一次网站全站http升级为https的过程,websocket : ws升级为wss遇到的问题等
2624 0
记一次网站全站http升级为https的过程,websocket : ws升级为wss遇到的问题等
|
7月前
|
网络安全 开发者
如何解决HTTPS协议在WordPress升级后对网站不兼容的问题
以上就是解决WordPress升级后HTTPS协议对网站的不兼容问题的方法。希望能把这个棘手的问题看成是学校的管理问题一样来应对,将复杂的技术问题变得更加有趣和形象,并寻觅出解决问题的方式。希望你的网站能在新的学期得到更好的发展!
218 19
|
安全 网络协议 算法
HTTPS为什么可以穿越NAT端口映射设备
HTTPS能穿越NAT端口映射设备的原因在于,NAT设备仅在IP和端口层面进行地址转换,不对应用层协议(如TLS)的内容进行解析或干预。因此,HTTPS的加密通信可在客户端与服务器间直接建立,NAT设备充当透明中介,确保数据包正确路由,而不涉及加密或认证过程。这样即使没有在NAT设备上配置证书,HTTPS连接也能顺利建立并保持安全。
345 6
|
安全 应用服务中间件 网络安全
简单比较 http https http2,我们要如何把http升级为https
【9月更文挑战第13天】本文对比了HTTP、HTTPS和HTTP/2的特点与适用场景。HTTP以明文传输,适合低安全要求的环境;HTTPS通过SSL/TLS加密,适用于电子商务等安全要求高的场景;HTTP/2采用二进制格式和多路复用,适合高性能Web应用。文章还详细介绍了将HTTP升级为HTTPS的步骤,包括申请和安装SSL证书、配置Web服务器、重定向HTTP流量到HTTPS以及测试HTTPS功能。升级到HTTPS可提高数据安全性和用户信任度。
599 13
|
安全 应用服务中间件 网络安全
修复HTTPS升级后出现 Mixed Content: The page at 'https://xxx' was loaded over HTTPS, but requested an insecure frame 'http://xxx'. This request has been blocked; the content must be served over HTTPS. 的问题
修复HTTPS升级后出现 Mixed Content: The page at 'https://xxx' was loaded over HTTPS, but requested an insecure frame 'http://xxx'. This request has been blocked; the content must be served over HTTPS. 的问题
|
JSON Dubbo JavaScript
Dubbo Triple 协议重磅升级:支持通过 HTTP 连通 Web 与后端微服务
Dubbo Triple 协议重磅升级:支持通过 HTTP 连通 Web 与后端微服务
1203 90
|
安全 搜索推荐 前端开发
【https】如何让http升级成https
文章详细讲解了如何让HTTP到HTTPS的操作过程
1512 0
【https】如何让http升级成https
|
域名解析 网络协议 安全
【域名解析DNS专栏】DNS-over-TLS与DNS-over-HTTPS:安全升级新标准
【5月更文挑战第26天】随着网络技术的发展,DNS协议面临安全挑战,DNS-over-TLS (DoT) 和 DNS-over-HTTPS (DoH) 作为解决方案出现,旨在通过加密增强隐私和安全。DoT使用TLS封装DNS查询,防止流量被窥探或篡改;DoH则利用HTTPS隐藏DNS查询。实施DoT需在客户端和服务器间建立TLS连接,DoH需DNS服务器支持HTTPS接口。这两种技术为网络安全提供支持,未来有望更广泛部署,提升网络环境的安全性。
1806 0
|
JSON Dubbo JavaScript
Dubbo3 Triple 协议重磅升级:支持通过 HTTP 连通Web与后端微服务
阿里 [HSF2 框架已经完成到 Dubbo3 的全面升级](https://ata.atatech.org/articles/11000209827?spm=ata.25287382.0.0.26577536vUxJq6),阅读本文了解 Triple 协议工作原理。更多技术内容分享,请参见[官网博客](https://cn.dubbo.apache.org/zh-cn/blog/) ## 全新
672 0
Dubbo3 Triple 协议重磅升级:支持通过 HTTP 连通Web与后端微服务
|
安全 JavaScript Java
[※]记一次网站全站http升级为https的过程,websocket : ws升级为wss遇到的问题等
[※]记一次网站全站http升级为https的过程,websocket : ws升级为wss遇到的问题等
1889 0
[※]记一次网站全站http升级为https的过程,websocket : ws升级为wss遇到的问题等
下一篇