当前位置:   article > 正文

ESP32入门基础之空中升级(OTA)_esp32 ota

esp32 ota


参考资料:

  1. 空中升级 (OTA)编程指南
  2. OTA 例程说明

1 OTA简介

2 OTA操作流程

3 OTA操作实例

3.1 使用http实现简单的OTA升级

参考例程:examples\system\ota\simple_ota_example

3.1.1 例程简介

3.1.2 在本地生成简单的HTTP服务器

  1. 选择要升级的程序(bin文件);在这里插入图片描述

  2. 打开命令行界面,并进入到包含要升级的程序的目录文件夹下;在这里插入图片描述

  3. 输入命令 python2 -m SimpleHTTPServer 8070(有些可能是python -m SimpleHTTPServer 8070),并执行;在这里插入图片描述

  4. 保持命令行模式软件不要关闭

  5. 在浏览器输入http://xxx.xxx.xxx.xxx:8070,验证http服务器是否成功;在这里插入图片描述
    命令行界面也有提示输出,执行的是GET操作;
    在这里插入图片描述

  6. 在接下来的实验中也要保持命令行模式不要关闭。

3.1.3 配置simple_ota_example例程

  1. 不要关闭http服务器的命令行界面;
  2. 重新打开一个命令行界面,进入simple_ota_example例程, 使用 idf.py menuconfig 指令进入菜单配置模式;
  3. 配置好串口、所连接的wif、确保分区表有两个OTA分区在这里插入图片描述
  4. 配置要升级的程序的URL在这里插入图片描述
  5. 最后编译程序并烧录到ESP32开发板在这里插入图片描述
  6. 到此说明程序升级完成

3.1.4 程序分析

  1. 芯片初始化及wifi连接
void app_main(void)
{
    /*省略了代码,主要作用是芯片初始化、wifi连接等*/
    xTaskCreate(&simple_ota_example_task, "ota_example_task", 8192, NULL, 5, NULL);
}
void simple_ota_example_task(void *pvParameter)
{
    ESP_LOGI(TAG, "Starting OTA example");

    esp_http_client_config_t config = {
        .url = CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL, //这里即升级程序的URL,在菜单中配置
        .cert_pem = (char *)server_cert_pem_start,  //https所需要的认证,但这里是http,所以并不需要用到
        .event_handler = _http_event_handler,       
    };
    esp_err_t ret = esp_https_ota(&config);  //连接http,并下载升级程序
    if (ret == ESP_OK) {
        esp_restart();      //下载程序成功,重启即执行升级程序
    } else {
        ESP_LOGE(TAG, "Firmware upgrade failed");
    }
    //一切正常的话不会执行到这里,如下升级程序下载失败则执行下列程序
    while (1) {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
		ESP_LOGI(TAG, "while ---");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

感觉这个例程没有太大的实用性,只是帮助了解OTA的基本操作。

3.2 使用阿里云物联网平台实现简单的OTA升级

3.2.1 新建工程

  1. 选择 app-MqttToAliyun 作为基础工程,在此基础上修改;
  2. 更改工程名为 app-AliyunOTA;

3.2.2 工程菜单配置

  1. 执行命令 idf.py menuconfig
  2. 修改分区表,如下在这里插入图片描述
  3. 修改Flash size,如下在这里插入图片描述Flash size 默认为2MB,但第二步分区表选择官方提供的OTA分区表(Factory app,two OTA definitions),所以需要4MB以上的空间,如果实际的ESP32开发板Flash size 小于4MB,则可以自定义分区表。
  4. 其余参数,如wifi、端口、波特率可根据实际情况定义

3.2.3 将升级程序上传到阿里云物联网平台

参考资料:阿里云物联网平台->设备端OTA升级

  1. 该工程是以 app-MqttToAliyun为基础,所以已经实现了ESP32设备与阿里云之间的通信。

  2. 打开阿里云物联网平台,定位到 “物联网平台/监控运维/OTA 升级 ” ,点击 “添加升级包”,如下在这里插入图片描述在这里插入图片描述填完参数,最后点击下方“确认”,升级包随便选择一个工程的.bin文件

  3. 升级包上传完成在这里插入图片描述

  4. 点击右方“批量升级”在这里插入图片描述在这里插入图片描述
    点击左下角 下一步 在这里插入图片描述

  5. 到这里阿里云物联网平台就配置完了,只要ESP32开发板连接到阿里云平物联网平台的 ESP8266-TEST产品下的dev-esp32设备,就会收到阿里云物联网平台推送的JSON数据,(当然ESP32开发板要实现了OTA程序)

3.2.4 下载阿里云物理网平台TLS根证书配置工程

  1. 因为阿里云物联网平台使用的是https协议,所以需要TLS证书,下载地址点击这里在这里插入图片描述
  2. 将阿里云服务器的TLS根证书替换到工程中的server_certs目录(如果没有则新建该目录),在这里插入图片描述
  3. 进入 main 目录下,打开 CMakeLists.txt 文件,添加 root.crt: EMBED_TXTFILES ${project_dir}/server_certs/root.crt在这里插入图片描述
  4. 打开 component.mk 文件,添加 root.crt: COMPONENT_EMBED_TXTFILES := ${PROJECT_PATH}/server_certs/root.crt在这里插入图片描述
  5. 注意在程序中,也需要做相应的修改,如下
extern const uint8_t server_root_crt_start[] asm("_binary_root_crt_start");  //注意该地方需要修改
extern const uint8_t server_root_crt_end[]   asm("_binary_root_crt_end");

	  esp_http_client_config_t config = {	  
	      .url = url_buf,
		  .cert_pem = (char *)server_root_crt_start, 
		  .event_handler = _http_event_handler,
	  };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3.2.5 工程编写函数

  1. 工程配置完成后,编译工程,下载程序到ESP32设备,ESP32成功连接到阿里云物联网平台后,会收到阿里云推送的OTA升级的JSON格式数据,该数据包含OTA升级包的URL、版本号等信息
    在这里插入图片描述该数据由如下函数接口打印:
static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
{
    esp_mqtt_client_handle_t client = event->client;
    int  msg_id;
	
    // your_context_t *context = event->context;
    switch (event->event_id) {
        case MQTT_EVENT_CONNECTED:
            break;
        case MQTT_EVENT_DISCONNECTED:
            break;
        case MQTT_EVENT_SUBSCRIBED:
            break;
        case MQTT_EVENT_UNSUBSCRIBED:
            break;
        case MQTT_EVENT_PUBLISHED:
            break;
        case MQTT_EVENT_DATA:
            ESP_LOGI(TAG, "MQTT_EVENT_DATA");
            printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);  //打印主题
            printf("DATA=%.*s\r\n", event->data_len, event->data);	   //打印数据
            break;
        case MQTT_EVENT_ERROR:
            break;
        default:
            break;
    }
    return ESP_OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  1. 该OTA升级的JSON数据,是按如下格式打印的,详细请参考:阿里云物联网平台设备端OTA升级在这里插入图片描述
  2. 将该OTA升级的JSON数据使用JSON数据在线解析工具解析,如下在这里插入图片描述
  3. 在工程中将OTA的JSON数据解析,并根据解析的URL下载升级包,最后重启ESP32
#define   AliyunSubscribeTopic_ota_upgrade  "/ota/device/upgrade/a1tUbQR2faQ/dev-esp32"
#define   AliyunPublishTopic_ota_inform     "/ota/device/inform/a1tUbQR2faQ/dev-esp32"

static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
{
    esp_mqtt_client_handle_t client = event->client;
    // your_context_t *context = event->context;
    switch (event->event_id) {
        ...
        case MQTT_EVENT_DATA:
            ESP_LOGI(TAG, "MQTT_EVENT_DATA");
            char *topicBuf = (char*)malloc(event->topic_len+1);
		   //void  *memcpy(void *s1,  const void *s2,  size_t  n); 函数memcpy从s2指向的对象中复制n个字符到s1指向的对象中。		   
           	memcpy(topicBuf, event->topic, event->topic_len);
			//printf("---Receive topic:\n %s \r\n", topicBuf);//打印接收的消息
			temp = strcmp(topicBuf,AliyunSubscribeTopic_ota_upgrade); //判断主题是否是OTA主题,如果是才调用OTA的JSON解析函数
		    if(0 == temp)	
		    {	
		    	ESP_LOGI(TAG, "OTA DATA PARSE");
		        //char  *strncpy(char *s2, const char *s1, size_t n);函数strncpy从s1指向的数组中最多复制n个字符(不复制空字符后面的字符)到s2指向的数组中。
				strncpy(local_data_buffer, event->data, event->data_len); //将指针类型的数据复制到一个数组中
				//printf("local_data_buffer:%s ", local_data_buffer); 
			    ret = user_parse_json(local_data_buffer,aliyun_ota_config);//解析数据,并使用解析出来的URL下载OTA升级包
				if (ret == ESP_OK) //解析并下载OTA升级包成功
				{
			        //构造JSON格式数据,该数据用于反馈给阿里云物联网平台,作用是通知升级包接收完成
					cJSON *Wroot =	cJSON_CreateObject();
					cJSON *Pitem =	cJSON_CreateObject();					
					cJSON_AddItemToObject(Wroot, "id", cJSON_CreateString("123"));
					cJSON_AddItemToObject(Wroot, "params", Pitem);
					cJSON_AddItemToObject(Pitem, "step", cJSON_CreateString("100"));
					cJSON_AddItemToObject(Pitem, "desc", cJSON_CreateString("OTA update successfully !"));
					cJSON_AddItemToObject(Pitem, "module", cJSON_CreateString("MCU"));				
					//printf("%s\n", cJSON_Print(Wroot)); //打印刚才构建的JSON数据,看是否正确
					char ota_inform_buf[512];
					int len = strlen(cJSON_Print(Wroot));					
					memcpy(ota_inform_buf, cJSON_Print(Wroot),len); //将JSON格式数据复制到数组中,将以数组的形式传递给发布函数
					ota_inform_buf[len] = '\0';
					printf("%s\n",ota_inform_buf);//打印数据是否正确
					//发布信息到阿里云物联网平台
		            msg_id = esp_mqtt_client_publish(client, AliyunPublishTopic_ota_inform, ota_inform_buf, strlen(ota_inform_buf), 0, 0);
		            ESP_LOGI(TAG, "sent publish ota inform successful, msg_id=%d", msg_id);		
					
//					cJSON_Delete(Wroot);  //执行这个函数会出错,不知道什么原因
//					cJSON_Delete(Pitem);
					esp_restart();  //ESP32设备重启,重启后将执行刚才下载的程序
				} 
				else 
				{
					ESP_LOGE(TAG, "Firmware upgrade failed");
			    }	
		    }
		    free(topicBuf);		
            break;
        ... 
        default:
            break;
    }
    return ESP_OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
 esp_err_t user_parse_json(char *json_data,user_aliyun_ota_config_t ota_config)
{
	cJSON *item = NULL;
	cJSON *root = NULL;
//root 开始-------------------------------------------------------------------------		
    root = cJSON_Parse(json_data);   /*json_data 阿里云OTA原始数据*/ 
    if (!root) 
    {
      printf("Error before: [%s]\n",cJSON_GetErrorPtr());	  
	  return  ESP_FAIL;
	}
	printf("%s\n\n", cJSON_Print(root));   /*将完整的数据以JSON格式打印出来*/
	
	item = cJSON_GetObjectItem(root, "code");
	ota_config.code = cJSON_Print(item);
	
//data 开始-------------------------------------------------------------------------	    		
	cJSON *Pdata = cJSON_GetObjectItem(root, "data");	
    item = cJSON_GetObjectItem(Pdata, "size");
    ota_config.size = item->valueint;
    
//extData 开始-------------------------------------------------------------------------		
	cJSON *PextData = cJSON_GetObjectItem(Pdata, "extData");
	item = cJSON_GetObjectItem(PextData, "_package_udi");
	ota_config._package_udi = cJSON_Print(item);  
//extData 结束------------------------------------------------------------------------- 	

	item = cJSON_GetObjectItem(Pdata, "sign");
	ota_config.sign = cJSON_Print(item);    

	item = cJSON_GetObjectItem(Pdata, "version");
	ota_config.version = cJSON_Print(item);    

	item = cJSON_GetObjectItem(Pdata, "url");
	ota_config.url = cJSON_Print(item);    

	item = cJSON_GetObjectItem(Pdata, "signMethod");
	ota_config.signMethod = cJSON_Print(item);    

	item = cJSON_GetObjectItem(Pdata, "md5");
	ota_config.md5 = cJSON_Print(item);
//data 结束-------------------------------------------------------------------------

	item = cJSON_GetObjectItem(root, "id");
	ota_config.id = item->valuedouble;
    
	item = cJSON_GetObjectItem(root, "message");
	ota_config.message = cJSON_Print(item);
//root 结束-------------------------------------------------------------------------    
//   cJSON_Delete(root);   //执行这个函数会出错,不知道什么原因
//   cJSON_Delete(Pdata);
//   cJSON_Delete(PextData);
//   cJSON_Delete(item);

//  printf("code:%s\n", ota_config.code);
//  printf("size:%d\n", ota_config.size);	
//  printf("_package_udi:%s\n", ota_config._package_udi);
//  printf("sign:%s\n", ota_config.sign);	
//	printf("version:%s\n", ota_config.version);
//  printf("url:%s\n", ota_config.url);	
//  printf("signMethod:%s\n", ota_config.signMethod);	
//  printf("md5:%s\n", ota_config.md5);	
//	printf("id:%f\n", ota_config.id);	
//	printf("message:%s\n", ota_config.message);	

	  char url_buf[OTA_URL_SIZE];
	  int len = strlen(ota_config.url);

	  memcpy(url_buf, ota_config.url, len); //将指针型数据复制到数组中,

//解析出来的URL包含了双引号"",但数组中的URL不能包含双引号""
	  for(int i = 0;i < len;i++ )
	  {
	     url_buf[i] = url_buf[i+1];   //为了去掉数组中的双引号“”,这里是前部分
	  }

	  url_buf[len - 2] = '\0';       //为了去掉数组中的双引号“”,这里是后部分

	  printf("buf:%s\n", url_buf);  //打印检查URL是否正确


	  esp_http_client_config_t config = {	  
	  	//. url = "https://xxx"  //这里需要双引号""
	      .url = url_buf,        //这里,数组中不能包含双引号""
		  .cert_pem = (char *)server_root_crt_start, 
		  .event_handler = _http_event_handler,
	  };
		
    esp_err_t ret = esp_https_ota(&config); //下载升级包等一系列操作

	return  ret;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92

3.2.6 实验分析

程序编写完成,编译下载到ESP32设备中,查看串口打印数据,如下

//数据开始
ets Jul 29 2019 12:21:46
...
I (61) boot: Partition Table: //分区表
I (64) boot: ## Label            Usage          Type ST Offset   Length
I (72) boot:  0 nvs              WiFi data        01 02 00009000 00004000
I (79) boot:  1 otadata          OTA data         01 00 0000d000 00002000
I (87) boot:  2 phy_init         RF data          01 01 0000f000 00001000
I (94) boot:  3 factory          factory app      00 00 00010000 00100000
I (102) boot:  4 ota_0            OTA app          00 10 00110000 00100000
I (109) boot:  5 ota_1            OTA app          00 11 00210000 00100000
I (117) boot: End of partition table
I (121) boot: Defaulting to factory image //刚编译并通过有线烧录,默认执行工厂镜像程序
...
I (498) boot: Loaded app from partition at offset 0x10000 //从偏移地址0x10000处加载程序
I (498) boot: Disabling RNG early entropy source...
I (498) cpu_start: Pro cpu up.
I (502) cpu_start: Application information:  //该程序信息
I (507) cpu_start: Project name:     app-MqttToAliyun
I (513) cpu_start: App version:      5204503a-dirty
I (518) cpu_start: Compile time:     Jul  3 2021 11:33:25
...
I (0) cpu_start: App cpu up.
...
I (1698) wifi station: connected to ap SSID:canbo-418-2.4G password:canbo418 //连接wifi
I (1708) MQTT_EXAMPLE: into mqtt_test_task //开始执行mqtt任务,即连接阿里云物联网平台
I (1708) MQTT_EXAMPLE: Other event id:7
I (1948) MQTT_EXAMPLE: MQTT_EVENT_CONNECTED
I (1948) MQTT_EXAMPLE: sent publish successful, msg_id=49855
I (1948) MQTT_EXAMPLE: sent subscribe successful, msg_id=15854
I (1998) MQTT_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=49855
I (2058) MQTT_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=15854
I (2068) MQTT_EXAMPLE: sent publish successful, msg_id=0
I (6228) MQTT_EXAMPLE: MQTT_EVENT_DATA
I (6238) MQTT_EXAMPLE: OTA DATA PARSE//收到阿里云物联网平台推送的OTA的JSON格式数据
{
        "code": "1000",
        "data": {
                "size": 822528,
                "extData":      {
                        "_package_udi": "这是阿里云OTA测试程序"
                },
                "sign": "72fd4a8b0e67fc0657b1ea707570e27a",
                "version":      "1.00",
                "url":  "https://iotx-ota.oss-cn-shanghai.aliyuncs.com/ota/6bc61a794bad89c4c1edf4ecf46a1666/ckqnivitr0003268hsmg81bac.bin?Expires=1625537056&OSSAccessKeyId=LTAI4G1TuWwSirnbAzUHfL3e&Signature=39CeoZ34CY1KucXl69yq1ajHqDw%3D",
                "signMethod":   "Md5",
                "md5":  "72fd4a8b0e67fc0657b1ea707570e27a"
        },
        "id":   1625450656015,
        "message":      "success"
}

buf:https://iotx-ota.oss-cn-shanghai.aliyuncs.com/ota/6bc61a794bad89c4c1edf4ecf46a1666/ckqnivitr0003268hsmg81bac.bin?Expires=1625537056&OSSAccessKeyId=LTAI4G1TuWwSirnbAzUHfL3e&Signature=39CeoZ34CY1KucXl69yq1ajHqDw%3D//解析出升级包的URL
I (7808) esp_https_ota: Starting OTA...//开始执行OTA下载等操作
I (7818) esp_https_ota: Writing to partition subtype 16 at offset 0x110000
I (8858) MQTT_EXAMPLE: while---//这里是无操作时while(1)执行的打印
I (15948) MQTT_EXAMPLE: while---
I (22208) esp_https_ota: Connection closed
//下载OTA升级包的一些打印信息
I (22218) esp_image: segment 0: paddr=0x00110020 vaddr=0x3f400020 size=0x1deec (122604) map
...
I (22808) esp_image: segment 5: paddr=0x001c3b1c vaddr=0x40080404 size=0x151b8 ( 86456)
//下面的JSON数据时发布到阿里云物联网的数据
{
        "id":   "123",
        "params":       {
                "step": "100",
                "desc": "OTA update successfully !",
                "module":       "MCU"
        }
}
I (22868) MQTT_EXAMPLE: sent publish ota inform successful, msg_id=0
//下面是执行了重启函数esp_restart();后关闭wifi等一系列操作
I (22868) wifi:state: run -> init (0)
I (22868) wifi:pm stop, total sleep time: 4226386 us / 21765363 us

I (22878) wifi:new:<11,0>, old:<11,0>, ap:<255,255>, sta:<11,0>, prof:1
W (22888) wifi:hmac tx: stop, discard
W (22888) wifi:hmac tx: stop, discard
I (22938) wifi:flush txq
I (22938) wifi:stop sw txq
I (22938) wifi:lmac stop hw txq

//下面是开始执行升级后的程序
ets Jul 29 2019 12:21:46
...
I (484) cpu_start: Pro cpu up.
I (487) cpu_start: Application information://这里的升级后的程序信息,和前面的不一样了
I (492) cpu_start: Project name:     app-AliyunFinishOTA 
I (498) cpu_start: App version:      5204503a-dirty
I (504) cpu_start: Compile time:     Jul  3 2021 16:21:00
..
I (513) cpu_start: App cpu up.
...
//下面执行的是升级后的程序
I (2184) wifi station: connected to ap SSID:canbo-418-2.4G password:canbo418//连接wifi
I (2194) MQTT_EXAMPLE: Other event id:7
I (2364) MQTT_EXAMPLE: MQTT_EVENT_CONNECTED
I (2374) MQTT_EXAMPLE: sent publish ota inform successful, msg_id=0
I (2374) MQTT_EXAMPLE: sent publish successful, msg_id=55995
I (2374) MQTT_EXAMPLE: sent subscribe successful, msg_id=39235
I (2484) MQTT_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=39235
I (2484) MQTT_EXAMPLE: sent publish successful, msg_id=0
I (2494) MQTT_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=55995
I (7194) MQTT_EXAMPLE: i am aliyun finish ota
I (7904) MQTT_EXAMPLE: MQTT_EVENT_DATA
TOPIC=/ota/device/upgrade/a1tUbQR2faQ/dev-esp32
DATA={"code":"1000","data":{"size":822528,"extData":{"_package_udi":"这是阿里云OTA测试程序"},"sign":"72fd4a8b0e67fc0657b1ea707570e27a","version":"1.00","url":"https://iotx-ota.oss-cn-shanghai.aliyuncs.com/ota/6bc61a794bad89c4c1edf4ecf46a1666/ckqnivitr0003268hsmg81bac.bin?Expires=1625537080&OSSAccessKeyId=LTAI4G1TuWwSirnbAzUHfL3e&Signature=o8nS68PWhNy2fAqvn5U5Soxaaco%3D","signMethod":"Md5","md5":"72fd4a8b0e67fc0657b1ea707570e27a"},"id":1625450680578,"message":"success"}
I (12194) MQTT_EXAMPLE: i am aliyun finish ota
I (17194) MQTT_EXAMPLE: i am aliyun finish ota

Done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

详细信息请自行测试
工程链接:app-AliyunOTA

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/600731
推荐阅读
相关标签
  

闽ICP备14008679号