Commit 50a056cf authored by 957dd's avatar 957dd

Initial commit

parents
CompileFlags:
Remove: [-f*, -m*]
ARG DOCKER_TAG=latest
FROM espressif/idf:${DOCKER_TAG}
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
RUN apt-get update -y && apt-get install udev -y
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
CMD ["/bin/bash", "-c"]
\ No newline at end of file
{
"name": "ESP-IDF QEMU",
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"idf.gitPath": "/usr/bin/git"
},
"extensions": [
"espressif.esp-idf-extension",
"espressif.esp-idf-web"
]
}
},
"runArgs": ["--privileged"]
}
\ No newline at end of file
# 编译输出
build/
# 组件管理器
managed_components/
# IDE配置
.vscode/
# # ESP-IDF配置文件(可选,看你要不要忽略)
# sdkconfig
# sdkconfig.old
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(remote-control)
dependencies:
espressif/cjson:
component_hash: 002c6d1872ee4c97d333938ebe107a29841cc847f9de89e676714bd2844057ea
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.7.19~1
espressif/mqtt:
component_hash: ffdad5659706b4dc14bc63f8eb73ef765efa015bf7e9adf71c813d52a2dc9342
dependencies:
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.0
idf:
source:
type: idf
version: 5.5.1
direct_dependencies:
- espressif/cjson
- espressif/mqtt
- idf
manifest_hash: 968efdfd16603f722e91d1be00040c4ca18d65ff821a4ade1a22016ee6b8495e
target: esp32c3
version: 2.0.0
idf_component_register(SRCS "main.c" "ota.c" "wifidevnum_config.c" "mqttconf_commun.c" "hardware_ctrl.c"
INCLUDE_DIRS "."
REQUIRES spiffs nvs_flash esp_wifi esp_event esp_http_server esp_http_client esp_https_ota mqtt json app_update esp_timer esp_netif driver lwip
)
spiffs_create_partition_image(storage ../spiffs FLASH_IN_PROJECT)
\ No newline at end of file
menu "My Application Configuration"
config MY_APP_VERSION
string "My App Version"
default "1.0.1"
help
The version of this application, used for OTA and MQTT heartbeats.
config TANK_REMOTE_MQTT_URL
string "Tank Remote MQTT URL"
default "https://fcrs-api.yd-ss.com/device/getConfig?deviceNo="
help
The base URL to fetch MQTT configurations.
config TANK_REMOTE_WIFI_SSID
string "Tank Remote WiFi AP SSID"
default "TANK_REMOTE_CFG_AP"
help
The SSID broadcasted in AP mode during configuration.
endmenu
This diff is collapsed.
#ifndef HARDWARE_CTRL_H
#define HARDWARE_CTRL_H
#include <stdbool.h>
#include "esp_err.h"
// GPIO control
void device_hardware_control(int pin, int val);
esp_err_t hardware_init();
// PWM control
void device_hardware_walk_control(int mode, int val);
void device_hardware_stop(void);
// Other hardware specific stubs
#endif
## IDF Component Manager Manifest File
dependencies:
## Required IDF version
idf:
version: '>=4.1.0'
# # Put list of dependencies here
# # For components maintained by Espressif:
# component: "~1.0.0"
# # For 3rd party components:
# username/component: ">=1.0.0,<2.0.0"
# username2/component2:
# version: "~1.0.0"
# # For transient dependencies `public` flag can be set.
# # `public` flag doesn't have an effect dependencies of the `main` component.
# # All dependencies of `main` are public by default.
# public: true
espressif/mqtt: ^1.0.0
espressif/cjson: ^1.7.19~1
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "hardware_ctrl.h"
#include "wifidevnum_config.h"
#include "mqttconf_commun.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_event.h"
#define DELAY_MS_PER_STEP (4700)
void app_main(void)
{
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// Initialize SPIFFS
init_spiffs();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(hardware_init());
// 3. Start System Tasks
// Start button monitor task for entering AP mode
xTaskCreate(button_monitor_task, "btn_monitor", 2048, NULL, 5, NULL);
// Block to connect to WiFi Station
if(connect_wifi_station()){
// Start MQTT and abnormal tasks only if WiFi connected successfully
xTaskCreate(config_pull_and_init_task, "mqtt_task", 8192, NULL, 5, NULL);
xTaskCreate(mqtt_abnormal_exittask, "mqtt_abnormal", 2048, NULL, 5, NULL);
} else {
ESP_LOGI("MAIN", "WiFi configuration missing or failed. Press Button 9 to enter AP Config Mode.");
// Open the AP setting webpage automatically
nowifidata_start_config_web();
}
// Main loop wait (Control is now handled by MQTT callbacks)
while (1) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
This diff is collapsed.
#ifndef __MQTTCONF_COMMUN_H__
#define __MQTTCONF_COMMUN_H__
#include "esp_err.h"
#define MQTT_SERVICE_NUM_MAX 10
// 启动所有 MQTT 相关逻辑
void config_pull_and_init_task(void *pvParameters); // Exposed for task_manager
void mqtt_manager_stop(void);
void mqtt_abnormal_exittask(void *pvParameters);
#endif
#include "ota.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_app_format.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "esp_crt_bundle.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "wifidevnum_config.h" // 假设你有封装好的 read_from_nvs 和 save_to_nvs
#include "esp_spiffs.h"
#include <cJSON.h>
#include <string.h>
static const char *TAG = "OTA_UPDATE";
/**
* @brief HTTP 事件处理
*/
esp_err_t _ota_http_event_handler(esp_http_client_event_t *evt) {
switch (evt->event_id) {
case HTTP_EVENT_ERROR: ESP_LOGE(TAG, "HTTP_EVENT_ERROR"); break;
case HTTP_EVENT_ON_CONNECTED: ESP_LOGI(TAG, "已连接到服务器"); break;
case HTTP_EVENT_ON_FINISH: ESP_LOGI(TAG, "数据传输完成"); break;
default: break;
}
return ESP_OK;
}
/**
* @brief 启动 OTA
*/
void start_ota_update(const char* url) {
ESP_LOGI(TAG, "正在从 URL 启动 OTA: %s", url);
esp_http_client_config_t config = {
.url = url,
.crt_bundle_attach = esp_crt_bundle_attach,
.event_handler = _ota_http_event_handler,
.keep_alive_enable = true,
.timeout_ms = 10000,
};
esp_https_ota_config_t ota_config = {
.http_config = &config,
};
ESP_LOGI(TAG, "正在下载并写入固件... 请勿断电");
esp_err_t ret = esp_https_ota(&ota_config);
// 在这里获取更新后的分区指针
const esp_partition_t *updated_partition = esp_ota_get_next_update_partition(NULL);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "OTA 升级成功!即将重启...");
ESP_LOGI(TAG, "找到更新分区: %s (偏移: 0x%08x)",
updated_partition->label, updated_partition->address);
esp_err_t set_err = esp_ota_set_boot_partition(updated_partition);
if (set_err == ESP_OK) {
ESP_LOGI(TAG, "启动分区设置成功!");
// 验证设置结果
const esp_partition_t *boot_partition = esp_ota_get_boot_partition();
const esp_partition_t *running_partition = esp_ota_get_running_partition();
ESP_LOGI(TAG, "当前运行分区: %s (0x%08x)",
running_partition->label, running_partition->address);
ESP_LOGI(TAG, "下次启动分区: %s (0x%08x)",
boot_partition->label, boot_partition->address);
// 等待设置完成
vTaskDelay(2000 / portTICK_PERIOD_MS);
esp_restart();
}else {
ESP_LOGE(TAG, "设置启动分区失败: %s", esp_err_to_name(set_err));
}
} else {
ESP_LOGE(TAG, "OTA 升级失败: %s", esp_err_to_name(ret));
}
}
/**
* @brief MQTT 消息处理函数:解析 JSON 并判断是否需要更新
*/
int ota_update_recmqtt(const char *json_data) {
if (json_data == NULL) return -1;
cJSON *root = cJSON_Parse(json_data);
if (root == NULL) return -1;
ESP_LOGI(TAG, "当前固件运行版本: %s", CONFIG_MY_APP_VERSION);
// 2. 解析云端发来的新版本号
cJSON *new_version_obj = cJSON_GetObjectItem(root, "new_version");
if (!cJSON_IsString(new_version_obj) || (new_version_obj->valuestring == NULL)) {
cJSON_Delete(root);
return -1;
}
const char* cloud_version = new_version_obj->valuestring;
// 3. 版本对比
if (strcmp(CONFIG_MY_APP_VERSION, cloud_version) == 0) {
ESP_LOGI(TAG, "当前已是最新版本 (%s),跳过更新。", CONFIG_MY_APP_VERSION);
cJSON_Delete(root);
return 0;
}
ESP_LOGI(TAG, "检测到新版本: %s -> %s",CONFIG_MY_APP_VERSION, cloud_version);
// 5. 解析下载地址并启动更新
cJSON *esp32_url = cJSON_GetObjectItem(root, "esp32_url");
if (cJSON_IsString(esp32_url) && (esp32_url->valuestring != NULL)) {
start_ota_update(esp32_url->valuestring);
} else {
ESP_LOGE(TAG, "JSON 中未找到有效的 esp32_url");
}
cJSON_Delete(root);
return 0;
}
#ifndef OTA_H
#define OTA_H
int ota_update_recmqtt(const char *json_data);
#endif // OTA_H
This diff is collapsed.
#ifndef WIFIDEVNUM_CONFIG_H
#define WIFIDEVNUM_CONFIG_H
#include "esp_err.h"
#include <stddef.h>
#include <stdbool.h>
#define BTN_WIFI_IO 9
#define BTN_DEVID_IO 4
esp_err_t init_spiffs(void);
void save_to_nvs(const char* key, const char* value);
esp_err_t read_from_nvs(const char* key, char* buf, size_t len);
void start_config_web(void);
void nowifidata_start_config_web(void);
void button_monitor_task(void* arg);
// New Network function
bool connect_wifi_station(void);
#endif // WIFIDEVNUM_CONFIG_H
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
otadata, data, ota, 0xf000, 0x2000,
phy_init, data, phy, 0x11000, 0x1000,
ota_0, app, ota_0, 0x20000, 0x1C0000,
ota_1, app, ota_1, 0x1E0000,0x1C0000,
storage, data, spiffs, 0x3A0000,0x50000,
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width,initial-scale=1.0'>
<style>
body { font-family: sans-serif; text-align: center; padding: 20px; background: #f0f2f5; }
.card { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); max-width: 380px; margin: auto; }
input { width: 90%; padding: 12px; margin: 10px 0; border-radius: 6px; border: 1px solid #ddd; }
.btn { width: 95%; padding: 15px; background: #28a745; color: white; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; }
b { display: block; text-align: left; margin-left: 5%; margin-top: 10px; color: #555; }
</style>
</head>
<body>
<div class="card">
<h1>🦉 飞驰设备配置中心</h1>
<form action='/save' method='POST'>
<b>WiFi 配置 %s</b>
<input name='ssid' placeholder='WiFi名称' %s>
<input name='pass' type='password' placeholder='WiFi密码' %s>
<br>
<b>设备 ID %s</b>
<input name='devid' placeholder='请输入设备号' %s>
<button type='submit' class='btn'>保存并重启设备</button>
</form>
</div>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment