diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 0852706594c222f30c3d86101393c2a87a31de66..96cff03f0cc3ac4fb986e62b51b7c3ed17625a71 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -3,4 +3,8 @@ idf_component_register(SRCS "app_main.c" "led.c" "tts.c" "provisioning.c" - INCLUDE_DIRS ".") + "user_mqtt.c" + "aliyun_ota.c" + "beep.c" + INCLUDE_DIRS "." + EMBED_TXTFILES ${project_dir}/server_certs/root.crt) diff --git a/main/aliyun_ota.c b/main/aliyun_ota.c new file mode 100644 index 0000000000000000000000000000000000000000..f10c0d0084c7fdeb07895f71f9a167e7f30506a9 --- /dev/null +++ b/main/aliyun_ota.c @@ -0,0 +1,156 @@ +/* OTA example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_ota_ops.h" +#include "esp_http_client.h" +#include "esp_https_ota.h" + +#include "string.h" +#include "mqtt_client.h" + + +#include "cJSON.h" + +#include "aliyun_ota.h" +#define VERSION "V1.5" + +#define OTA_URL_SIZE 256 + + +static const char *TAG = "simple_ota_example"; +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"); + +char version_get; + + esp_err_t _http_event_handler(esp_http_client_event_t *evt) + { + switch (evt->event_id) { + case HTTP_EVENT_ERROR: + ESP_LOGD(TAG, "HTTP_EVENT_ERROR"); + break; + case HTTP_EVENT_ON_CONNECTED: + ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED"); + break; + case HTTP_EVENT_HEADER_SENT: + ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT"); + break; + case HTTP_EVENT_ON_HEADER: + ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value); + break; + case HTTP_EVENT_ON_DATA: + ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len); + break; + case HTTP_EVENT_ON_FINISH: + ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH"); + break; + case HTTP_EVENT_DISCONNECTED: + ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED"); + break; + } + return ESP_OK; + } + + + 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); +// version_get = ota_config.version; +// if(strcmp(version_get, VERSION) != 0) +// { +// return ESP_FAIL; +// } + + 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); + + + 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; +} + + + + + diff --git a/main/aliyun_ota.h b/main/aliyun_ota.h new file mode 100644 index 0000000000000000000000000000000000000000..32ed5a9318f49a92fa5b550bd52e850faf3247b9 --- /dev/null +++ b/main/aliyun_ota.h @@ -0,0 +1,33 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief 闃块噷浜戠墿鑱旂綉骞冲彴OTA杩斿洖鏁版嵁锛?鏁版嵁缁撴瀯浣? + */ +typedef struct { + char *code ; + int size ; + char *_package_udi; + char *sign; + char *version; + char *url; + char *signMethod; + char *md5; + double id; + char *message; + +} user_aliyun_ota_config_t; + + +esp_err_t user_parse_json(char *json_data,user_aliyun_ota_config_t ota_config); + + + + +#ifdef __cplusplus +} +#endif + diff --git a/main/app_main.c b/main/app_main.c index c3f3005eec8ccddfc50143dd8e6208e23227ebf0..3a58bfdad6e5dd51b5387d26f900d25d5be2d630 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -40,8 +40,15 @@ #include "led.h" #include "tts.h" #include "dwm_api.h" +#include "beep.h" + +//OTA +#include "user_mqtt.h" +#include "aliyun_ota.h" +#include "cJSON.h" + +//OTA -#define BEEP_PIN 33 static const char *TAG = "FHPL_ESP32_DEMO"; @@ -60,24 +67,6 @@ static char sub_topic_voice[TOPIC_LEN_MAX]=""; static char sub_topic_beep[TOPIC_LEN_MAX]=""; static char sub_topic_light[TOPIC_LEN_MAX]=""; -static void beep_init(void) -{ - /*beep gpio set*/ - gpio_set_level(BEEP_PIN, 0); - gpio_reset_pin(BEEP_PIN); - gpio_pad_select_gpio(BEEP_PIN); - gpio_set_direction(BEEP_PIN, GPIO_MODE_OUTPUT); -} - -static void beep_on(void) -{ - gpio_set_level(BEEP_PIN, 1); -} - -static void beep_off(void) -{ - gpio_set_level(BEEP_PIN, 0); -} static void topic_fill_device_id(void) { @@ -327,6 +316,7 @@ void app_main(void) mqtt_app_start(); + /* NMEA parser configuration */ rtk_config_t config = NMEA_PARSER_CONFIG_DEFAULT(); @@ -335,4 +325,12 @@ void app_main(void) /* register event handler for NMEA parser library */ rtk_add_handler(rtk_hdl, gps_event_handler, NULL); + //OTA + + user_mqtt_app_start(); + + + + //OTA + } diff --git a/main/beep.c b/main/beep.c new file mode 100644 index 0000000000000000000000000000000000000000..8908a247c0b8f0e7f87d632bf6048fc04233d39a --- /dev/null +++ b/main/beep.c @@ -0,0 +1,34 @@ +/* + * beep.c + * + * Created on: 2022年5月4日 + * Author: ZSJ + */ +#include +#include "beep.h" +#include "driver/gpio.h" + +#define BEEP_PIN 33 + + +void beep_init(void) +{ + /*beep gpio set*/ + gpio_set_level(BEEP_PIN, 0); + gpio_reset_pin(BEEP_PIN); + gpio_pad_select_gpio(BEEP_PIN); + gpio_set_direction(BEEP_PIN, GPIO_MODE_OUTPUT); +} + +void beep_on(void) +{ + gpio_set_level(BEEP_PIN, 1); +} + +void beep_off(void) +{ + gpio_set_level(BEEP_PIN, 0); +} + + + diff --git a/main/beep.h b/main/beep.h new file mode 100644 index 0000000000000000000000000000000000000000..1f08c66a9908bbc5c0bc400d6d3dc7da935dedf0 --- /dev/null +++ b/main/beep.h @@ -0,0 +1,19 @@ +/* + * beep.h + * + * Created on: 2022年5月4日 + * Author: ZSJ + */ + +#ifndef MAIN_BEEP_H_ +#define MAIN_BEEP_H_ + + +void beep_init(void); +void beep_off(void); +void beep_on(void); + + + + +#endif /* MAIN_BEEP_H_ */ diff --git a/main/user_mqtt.c b/main/user_mqtt.c new file mode 100644 index 0000000000000000000000000000000000000000..f5541fbf8cc3644783953bcf213996f394a84728 --- /dev/null +++ b/main/user_mqtt.c @@ -0,0 +1,215 @@ +/* MQTT (over TCP) Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include "esp_wifi.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "esp_netif.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" + +#include "lwip/sockets.h" +#include "lwip/dns.h" +#include "lwip/netdb.h" + +#include "esp_log.h" +#include "mqtt_client.h" +#include "os.h" + +#include "cJSON.h" + +#include "user_mqtt.h" +#include "aliyun_ota.h" +#include "beep.h" + + +static const char *TAG = "MQTT_EXAMPLE"; + +/* + * 以下为阿里云信息配置,用于ESP32与阿里云取得连接 + */ + +/*Broker Address:${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com*/ +#define Aliyun_host "iot-06z00c3u82mzezw.mqtt.iothub.aliyuncs.com" +#define Aliyun_port 1883 +/*Client ID: ${ClientID}|securemode=${Mode},signmethod=${SignMethod}|*/ +#define Aliyun_client_id "h69tvsSgWA3.ESP32-DevKitC|securemode=2,signmethod=hmacsha256,timestamp=1651310639516|" +/*User Name: ${DeviceName}&${ProductKey}*/ +#define Aliyun_username "ESP32-DevKitC&h69tvsSgWA3" +/*使用官网 MQTT_Password 工具生成*/ +#define Aliyun_password "8381367c0d5d89f794403802fdfacdb697ce4fcbf65d835ba9b31f70b17efd4d" + + +#define AliyunSubscribeTopic_user_get "/h69tvsSgWA3/ESP32-DevKitC/user/get" +#define AliyunPublishTopic_user_update "/h69tvsSgWA3/ESP32-DevKitC/user/update" +#define AliyunSubscribeTopic_ota_upgrade "/ota/device/upgrade/h69tvsSgWA3/ESP32-DevKitC" +#define AliyunPublishTopic_ota_inform "/ota/device/inform/h69tvsSgWA3/ESP32-DevKitC" + +char local_data_buffer[1024] = {0}; + + +char mqtt_publish_data1[] = "mqtt connect ok "; +char mqtt_publish_data2[] = "mqtt subscribe successful"; +char mqtt_publish_data3[] = "mqtt i am esp32"; + +esp_mqtt_client_handle_t client; +user_aliyun_ota_config_t aliyun_ota_config; + + + +static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) +{ + esp_err_t ret; + + esp_mqtt_client_handle_t client = event->client; + int msg_id; + uint8_t temp; + + + // your_context_t *context = event->context; + switch (event->event_id) { + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + msg_id = esp_mqtt_client_publish(client, AliyunPublishTopic_user_update, mqtt_publish_data1, strlen(mqtt_publish_data1), 1, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + + msg_id = esp_mqtt_client_subscribe(client, AliyunSubscribeTopic_user_get, 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + break; + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + break; + + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + msg_id = esp_mqtt_client_publish(client, AliyunPublishTopic_user_update, mqtt_publish_data2, strlen(mqtt_publish_data2), 0, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + 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); + + ESP_LOGI(TAG, "this is fifth time!"); + + temp = strncmp(event->topic, AliyunSubscribeTopic_ota_upgrade, event->topic_len);//判断主题是否是OTA主题,如果是才调用OTA的JSON解析函数 + + if(0 == temp)//是OTA升级主题 + { + 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("ESP32")); + + //beep x4 OTA更新成功 + beep_on(); + usleep(50*1000); + beep_off(); + usleep(50*1000); + beep_on(); + usleep(50*1000); + beep_off(); + usleep(50*1000); + beep_on(); + usleep(50*1000); + beep_off(); + usleep(50*1000); + beep_on(); + usleep(50*1000); + beep_off(); + usleep(50*1000); + + + //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); + + esp_restart(); //ESP32设备重启,重启后将执行刚才下载的程序 + } + else + { + ESP_LOGE(TAG, "Firmware upgrade failed"); + } + + + } + //free(topicBuf); + break; + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + break; + default: + ESP_LOGI(TAG, "Other event id:%d", event->event_id); + break; + } + return ESP_OK; +} + + + + +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { + ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id); + mqtt_event_handler_cb(event_data); + +} + + + +void user_mqtt_app_start(void) +{ + esp_mqtt_client_config_t mqtt_cfg = { + .host = Aliyun_host, + .port = Aliyun_port, + .client_id = Aliyun_client_id, + .username = Aliyun_username, + .password = Aliyun_password, + + }; + + client = esp_mqtt_client_init(&mqtt_cfg); + esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client); + esp_mqtt_client_start(client); + +} + diff --git a/main/user_mqtt.h b/main/user_mqtt.h new file mode 100644 index 0000000000000000000000000000000000000000..3ecc769476188d1b45c51cc12eef46ce667309a1 --- /dev/null +++ b/main/user_mqtt.h @@ -0,0 +1,14 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + + + +void user_mqtt_app_start(void); + +#ifdef __cplusplus +} +#endif + diff --git a/partitions.csv b/partitions.csv index a3c455bc4a1ff4663fe5b0cd830ff16805f152f9..7bc7da523d8aca746969fb92c7492ae374dfc32e 100644 --- a/partitions.csv +++ b/partitions.csv @@ -1,5 +1,8 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap -nvs, data, nvs, 0x9000, 0x6000, +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap,,,, +nvs, data, nvs, 0x9000, 0x4000, +otadata,data,ota,0xd000,0x2000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 2000000, +factory, app, factory, 0x10000,2000000, +ota_0,app,ota_0,0x210000,2000000, +ota_1,app,ota_1,0x410000,2000000, diff --git a/server_certs/root.crt b/server_certs/root.crt new file mode 100644 index 0000000000000000000000000000000000000000..c44534c66c38d8d2d094eac45a446c7bd9daac02 --- /dev/null +++ b/server_certs/root.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- \ No newline at end of file