Fix upload page to split html

This commit is contained in:
2025-07-17 18:21:34 -06:00
parent c163389160
commit c4db3cbadc

View File

@ -21,157 +21,6 @@
static const char *TAG = "OTA_SERVER";
// HTML page for OTA update
static const char *ota_html =
"<!DOCTYPE html>"
"<html>"
"<head>"
"<title>ESP32 OTA Update</title>"
"<meta name='viewport' content='width=device-width, initial-scale=1'>"
"<style>"
"body { font-family: Arial, sans-serif; margin: 40px; background-color: #f0f0f0; }"
".container { max-width: 600px; margin: 0 auto; background-color: white; padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }"
"h1 { color: #333; text-align: center; }"
".info { background-color: #e7f3ff; border-left: 4px solid #2196F3; padding: 10px; margin-bottom: 20px; }"
".upload-area { border: 2px dashed #ccc; border-radius: 5px; padding: 30px; text-align: center; margin: 20px 0; }"
".upload-area.dragover { background-color: #e7f3ff; border-color: #2196F3; }"
"input[type='file'] { display: none; }"
".btn { background-color: #4CAF50; color: white; padding: 12px 24px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; }"
".btn:hover { background-color: #45a049; }"
".btn:disabled { background-color: #cccccc; cursor: not-allowed; }"
".progress { width: 100%; background-color: #f0f0f0; border-radius: 4px; margin-top: 20px; display: none; }"
".progress-bar { width: 0%; height: 30px; background-color: #4CAF50; border-radius: 4px; text-align: center; line-height: 30px; color: white; transition: width 0.3s; }"
".status { margin-top: 20px; padding: 10px; border-radius: 4px; display: none; }"
".status.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }"
".status.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }"
".file-info { margin-top: 10px; font-style: italic; color: #666; }"
"</style>"
"</head>"
"<body>"
"<div class='container'>"
"<h1>ESP32 OTA Update</h1>"
"<div class='info'>"
"<strong>Current Version:</strong> <span id='version'>%s</span><br>"
"<strong>Free Space:</strong> <span id='free-space'>%u KB</span>"
"</div>"
"<div class='upload-area' id='upload-area'>"
"<p>Drag and drop firmware file here or click to select</p>"
"<input type='file' id='file' accept='.bin'>"
"<button class='btn' onclick='document.getElementById(\"file\").click()'>Select File</button>"
"<div class='file-info' id='file-info'></div>"
"</div>"
"<button class='btn' id='upload-btn' onclick='uploadFirmware()' disabled>Upload Firmware</button>"
"<div class='progress' id='progress'>"
"<div class='progress-bar' id='progress-bar'>0%%</div>"
"</div>"
"<div class='status' id='status'></div>"
"</div>"
"<script>"
"console.log('OTA page loaded');"
"let selectedFile = null;"
"const uploadArea = document.getElementById('upload-area');"
"const fileInput = document.getElementById('file');"
"const uploadBtn = document.getElementById('upload-btn');"
"const progressDiv = document.getElementById('progress');"
"const progressBar = document.getElementById('progress-bar');"
"const statusDiv = document.getElementById('status');"
"const fileInfo = document.getElementById('file-info');"
""
"// File input change handler"
"fileInput.addEventListener('change', function(e) {"
" console.log('File input changed', e.target.files);"
" if (e.target.files.length > 0) {"
" handleFile(e.target.files[0]);"
" }"
"});"
""
"// Drag and drop handlers"
"uploadArea.addEventListener('dragover', function(e) {"
" e.preventDefault();"
" uploadArea.classList.add('dragover');"
"});"
""
"uploadArea.addEventListener('dragleave', function() {"
" uploadArea.classList.remove('dragover');"
"});"
""
"uploadArea.addEventListener('drop', function(e) {"
" e.preventDefault();"
" uploadArea.classList.remove('dragover');"
" const files = e.dataTransfer.files;"
" console.log('Files dropped:', files);"
" if (files.length > 0) {"
" handleFile(files[0]);"
" }"
"});"
""
"function handleFile(file) {"
" console.log('Handling file:', file.name, file.size);"
" if (file.name.toLowerCase().endsWith('.bin')) {"
" selectedFile = file;"
" fileInfo.textContent = 'Selected: ' + file.name + ' (' + (file.size/1024).toFixed(2) + ' KB)';"
" uploadBtn.disabled = false;"
" uploadBtn.textContent = 'Upload ' + file.name;"
" } else {"
" alert('Please select a .bin file');"
" selectedFile = null;"
" fileInfo.textContent = '';"
" uploadBtn.disabled = true;"
" uploadBtn.textContent = 'Upload Firmware';"
" }"
"}"
""
"function showStatus(message, type) {"
" statusDiv.textContent = message;"
" statusDiv.className = 'status ' + type;"
" statusDiv.style.display = 'block';"
"}"
""
"function uploadFirmware() {"
" if (!selectedFile) {"
" console.error('No file selected');"
" return;"
" }"
" "
" console.log('Starting upload...');"
" const xhr = new XMLHttpRequest();"
" uploadBtn.disabled = true;"
" progressDiv.style.display = 'block';"
" statusDiv.style.display = 'none';"
" "
" xhr.upload.addEventListener('progress', function(e) {"
" if (e.lengthComputable) {"
" const percent = Math.round((e.loaded / e.total) * 100);"
" progressBar.style.width = percent + '%%';"
" progressBar.textContent = percent + '%%';"
" console.log('Upload progress:', percent);"
" }"
" });"
" "
" xhr.addEventListener('load', function() {"
" console.log('Upload complete, status:', xhr.status);"
" if (xhr.status === 200) {"
" showStatus('Firmware uploaded successfully! Device will restart...', 'success');"
" setTimeout(function() { location.reload(); }, 5000);"
" } else {"
" showStatus('Upload failed: ' + xhr.responseText, 'error');"
" uploadBtn.disabled = false;"
" }"
" });"
" "
" xhr.addEventListener('error', function() {"
" console.error('Upload error');"
" showStatus('Upload error occurred', 'error');"
" uploadBtn.disabled = false;"
" });"
" "
" xhr.open('POST', '/update');"
" xhr.send(selectedFile);"
"}"
"</script>"
"</body>"
"</html>";
// Server handle
static httpd_handle_t s_server = NULL;
@ -208,20 +57,179 @@ static esp_err_t index_handler(httpd_req_t *req)
}
esp_partition_iterator_release(it);
// Allocate buffer for response
size_t response_size = strlen(ota_html) + 64;
char *response = malloc(response_size);
if (!response) {
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Memory allocation failed");
return ESP_FAIL;
}
snprintf(response, response_size, ota_html, s_version, free_space / 1024);
// Send response in chunks
httpd_resp_set_type(req, "text/html");
httpd_resp_send(req, response, strlen(response));
free(response);
// Part 1: HTML head and styles
const char *html_part1 =
"<!DOCTYPE html>"
"<html>"
"<head>"
"<title>ESP32 OTA Update</title>"
"<meta name='viewport' content='width=device-width, initial-scale=1'>"
"<style>"
"body { font-family: Arial, sans-serif; margin: 40px; background-color: #f0f0f0; }"
".container { max-width: 600px; margin: 0 auto; background-color: white; padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }"
"h1 { color: #333; text-align: center; }"
".info { background-color: #e7f3ff; border-left: 4px solid #2196F3; padding: 10px; margin-bottom: 20px; }"
".upload-area { border: 2px dashed #ccc; border-radius: 5px; padding: 30px; text-align: center; margin: 20px 0; }"
".upload-area.dragover { background-color: #e7f3ff; border-color: #2196F3; }"
"input[type='file'] { display: none; }"
".btn { background-color: #4CAF50; color: white; padding: 12px 24px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; }"
".btn:hover { background-color: #45a049; }"
".btn:disabled { background-color: #cccccc; cursor: not-allowed; }"
".progress { width: 100%; background-color: #f0f0f0; border-radius: 4px; margin-top: 20px; display: none; }"
".progress-bar { width: 0%; height: 30px; background-color: #4CAF50; border-radius: 4px; text-align: center; line-height: 30px; color: white; transition: width 0.3s; }"
".status { margin-top: 20px; padding: 10px; border-radius: 4px; display: none; }"
".status.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }"
".status.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }"
".file-info { margin-top: 10px; font-style: italic; color: #666; }"
"</style>"
"</head>"
"<body>"
"<div class='container'>"
"<h1>ESP32 OTA Update</h1>";
httpd_resp_send_chunk(req, html_part1, strlen(html_part1));
// Part 2: Info section with dynamic content
char info_buf[256];
snprintf(info_buf, sizeof(info_buf),
"<div class='info'>"
"<strong>Current Version:</strong> <span id='version'>%s</span><br>"
"<strong>Free Space:</strong> <span id='free-space'>%lu KB</span>"
"</div>", s_version, (unsigned long)(free_space / 1024));
httpd_resp_send_chunk(req, info_buf, strlen(info_buf));
// Part 3: Upload area
const char *html_part3 =
"<div class='upload-area' id='upload-area'>"
"<p>Drag and drop firmware file here or click to select</p>"
"<input type='file' id='file' accept='.bin'>"
"<button class='btn' onclick='document.getElementById(\"file\").click()'>Select File</button>"
"<div class='file-info' id='file-info'></div>"
"</div>"
"<button class='btn' id='upload-btn' onclick='uploadFirmware()' disabled>Upload Firmware</button>"
"<div class='progress' id='progress'>"
"<div class='progress-bar' id='progress-bar'>0%</div>"
"</div>"
"<div class='status' id='status'></div>"
"</div>";
httpd_resp_send_chunk(req, html_part3, strlen(html_part3));
// Part 4: JavaScript
const char *html_part4 =
"<script>"
"console.log('OTA page loaded');"
"let selectedFile = null;"
"const uploadArea = document.getElementById('upload-area');"
"const fileInput = document.getElementById('file');"
"const uploadBtn = document.getElementById('upload-btn');"
"const progressDiv = document.getElementById('progress');"
"const progressBar = document.getElementById('progress-bar');"
"const statusDiv = document.getElementById('status');"
"const fileInfo = document.getElementById('file-info');"
""
"fileInput.addEventListener('change', function(e) {"
" console.log('File input changed', e.target.files);"
" if (e.target.files.length > 0) {"
" handleFile(e.target.files[0]);"
" }"
"});"
""
"uploadArea.addEventListener('dragover', function(e) {"
" e.preventDefault();"
" uploadArea.classList.add('dragover');"
"});"
""
"uploadArea.addEventListener('dragleave', function() {"
" uploadArea.classList.remove('dragover');"
"});"
""
"uploadArea.addEventListener('drop', function(e) {"
" e.preventDefault();"
" uploadArea.classList.remove('dragover');"
" const files = e.dataTransfer.files;"
" console.log('Files dropped:', files);"
" if (files.length > 0) {"
" handleFile(files[0]);"
" }"
"});"
""
"function handleFile(file) {"
" console.log('Handling file:', file.name, file.size);"
" if (file.name.toLowerCase().endsWith('.bin')) {"
" selectedFile = file;"
" fileInfo.textContent = 'Selected: ' + file.name + ' (' + (file.size/1024).toFixed(2) + ' KB)';"
" uploadBtn.disabled = false;"
" uploadBtn.textContent = 'Upload ' + file.name;"
" } else {"
" alert('Please select a .bin file');"
" selectedFile = null;"
" fileInfo.textContent = '';"
" uploadBtn.disabled = true;"
" uploadBtn.textContent = 'Upload Firmware';"
" }"
"}"
""
"function showStatus(message, type) {"
" statusDiv.textContent = message;"
" statusDiv.className = 'status ' + type;"
" statusDiv.style.display = 'block';"
"}"
""
"function uploadFirmware() {"
" if (!selectedFile) {"
" console.error('No file selected');"
" return;"
" }"
" "
" console.log('Starting upload...');"
" const xhr = new XMLHttpRequest();"
" uploadBtn.disabled = true;"
" progressDiv.style.display = 'block';"
" statusDiv.style.display = 'none';"
" "
" xhr.upload.addEventListener('progress', function(e) {"
" if (e.lengthComputable) {"
" const percent = Math.round((e.loaded / e.total) * 100);"
" progressBar.style.width = percent + '%';"
" progressBar.textContent = percent + '%';"
" console.log('Upload progress:', percent);"
" }"
" });"
" "
" xhr.addEventListener('load', function() {"
" console.log('Upload complete, status:', xhr.status);"
" if (xhr.status === 200) {"
" showStatus('Firmware uploaded successfully! Device will restart...', 'success');"
" setTimeout(function() { location.reload(); }, 5000);"
" } else {"
" showStatus('Upload failed: ' + xhr.responseText, 'error');"
" uploadBtn.disabled = false;"
" }"
" });"
" "
" xhr.addEventListener('error', function() {"
" console.error('Upload error');"
" showStatus('Upload error occurred', 'error');"
" uploadBtn.disabled = false;"
" });"
" "
" xhr.open('POST', '/update');"
" xhr.send(selectedFile);"
"}"
"</script>"
"</body>"
"</html>";
httpd_resp_send_chunk(req, html_part4, strlen(html_part4));
// Send final chunk to complete response
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}