OTA works, log download works, integrated OTA build sys
This commit is contained in:
8
.externalToolBuilders/OTA SC-F001.launch
Normal file
8
.externalToolBuilders/OTA SC-F001.launch
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/SC-F001/ota_deploy.bat}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/SC-F001}"/>
|
||||
</launchConfiguration>
|
||||
10
.project
10
.project
@@ -11,6 +11,16 @@
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
|
||||
<triggers>full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>LaunchConfigHandle</key>
|
||||
<value><project>/.externalToolBuilders/OTA SC-F001.launch</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(app-template)
|
||||
project(SC-F001)
|
||||
|
||||
@@ -50,7 +50,7 @@ void setRelay(int8_t relay, bool state) {
|
||||
|
||||
void driveRelays() {
|
||||
uint8_t state = 0x00;
|
||||
relay_states[0] = (current_time / 1000000) % 2;
|
||||
//relay_states[0] = (current_time / 1000000) % 2; // for testing purposes
|
||||
|
||||
for (uint8_t i=0; i<8; i++) {
|
||||
// if we command and efuse permits it set the relay
|
||||
@@ -60,7 +60,7 @@ void driveRelays() {
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "RELAY STATE: %x", state);
|
||||
//ESP_LOGI(TAG, "RELAY STATE: %x", state);
|
||||
i2c_set_relays(state);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,26 @@
|
||||
<td><input type="datetime-local" id="in_time" step="1" onchange="markChanged(this)"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr><td colspan="4"><button id="commit_btn" onclick="commit_params()" disabled>Save Changes</button></td></tr>
|
||||
<tr><td colspan="4">
|
||||
<button id="commit_btn" onclick="commit_params()" disabled>Save Changes</button>
|
||||
</td></tr>
|
||||
</table>
|
||||
<table id="table2">
|
||||
<tr>
|
||||
<td>Firmware</td>
|
||||
<td><input type="file" id="firmware_file" accept=".bin"></td>
|
||||
<td><button id="upload_btn" onclick="uploadFirmware()">Upload Firmware</button></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Log File</td>
|
||||
<td><button id="log_btn" onclick="downloadLogFile()">Download Log</button></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<input type="file" id="firmware_file" accept=".bin">
|
||||
<button id="upload_btn" onclick="uploadFirmware()">Upload Firmware</button>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
let param_values = [];
|
||||
@@ -152,6 +167,38 @@
|
||||
xhr.send(file);
|
||||
}
|
||||
|
||||
async function downloadLogFile() {
|
||||
try {
|
||||
const response = await fetch('/log');
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const blob = await response.blob();
|
||||
|
||||
// Get current date and time
|
||||
const now = new Date();
|
||||
const day = String(now.getDate()).padStart(2, '0');
|
||||
const monthNames = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'];
|
||||
const month = monthNames[now.getMonth()];
|
||||
const year = now.getFullYear();
|
||||
const hours = String(now.getHours()).padStart(2, '0');
|
||||
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||
|
||||
const formattedDate = `${day}${month}${year}-${hours}${minutes}`;
|
||||
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `storage-${formattedDate}.bin`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error('Download failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Initial Load
|
||||
window.onload = fetchStatus;
|
||||
</script>
|
||||
|
||||
@@ -125,7 +125,7 @@ esp_err_t process_battery_voltage(void)
|
||||
} else {
|
||||
float alpha = get_param_value_t(PARAM_ADC_ALPHA_BATTERY).f32;
|
||||
if (isnan(raw)) {
|
||||
ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
//ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
} else {
|
||||
if (isnan(ema_battery) || isnan(alpha))
|
||||
ema_battery = raw;
|
||||
@@ -184,7 +184,7 @@ esp_err_t process_bridge_current(bridge_t bridge) {
|
||||
} else {
|
||||
float alpha = get_param_value_t(PARAM_ADC_ALPHA_ISENS).f32;
|
||||
if (isnan(raw_a)) {
|
||||
ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
//ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
channel->ema_current = NAN;
|
||||
} else {
|
||||
if (isnan(ema_battery) || isnan(alpha))
|
||||
@@ -206,7 +206,7 @@ esp_err_t process_bridge_current(bridge_t bridge) {
|
||||
} else {
|
||||
float alpha = get_param_value_t(PARAM_ADC_ALPHA_IAZ).f32;
|
||||
if (isnan(raw_a)) {
|
||||
ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
//ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
} else {
|
||||
if (isnan(ema_battery) || isnan(alpha))
|
||||
channel->az_offset = channel->ema_current;
|
||||
@@ -248,7 +248,7 @@ esp_err_t process_bridge_current(bridge_t bridge) {
|
||||
if (I_norm >= get_param_value_t(PARAM_EFUSE_KINST).f32) {
|
||||
channel->tripped = true;
|
||||
channel->trip_time = now;
|
||||
ESP_LOGI(TAG, "FUSE TRIP: Inom: %+.5f HEAT:%+2.5f", I_norm, channel->heat);
|
||||
//ESP_LOGI(TAG, "FUSE TRIP: Inom: %+.5f HEAT:%+2.5f", I_norm, channel->heat);
|
||||
return ESP_OK; // no more processing, if we're over, we're over
|
||||
}
|
||||
|
||||
@@ -280,8 +280,8 @@ esp_err_t process_bridge_current(bridge_t bridge) {
|
||||
// channel.heat = 0.0f // I think we should wait for the e-fuse to catch up
|
||||
}
|
||||
|
||||
if (bridge == BRIDGE_DRIVE)
|
||||
ESP_LOGI(TAG, "FUSE: Inom: %+.5f HEAT:%+2.5f", I_norm, channel->heat);
|
||||
//if (bridge == BRIDGE_DRIVE)
|
||||
// ESP_LOGI(TAG, "FUSE: Inom: %+.5f HEAT:%+2.5f", I_norm, channel->heat);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
120
main/rf_433.c
120
main/rf_433.c
@@ -37,9 +37,6 @@ typedef struct {
|
||||
size_t num_symbols;
|
||||
} rf_code_t;
|
||||
|
||||
// Global queue for passing decoded codes between tasks
|
||||
static QueueHandle_t g_code_queue = NULL;
|
||||
|
||||
int learn_flag = -1;
|
||||
|
||||
// For rmt_rx_register_event_callbacks
|
||||
@@ -52,8 +49,8 @@ static bool rfrx_done(rmt_channel_handle_t channel, const rmt_rx_done_event_data
|
||||
|
||||
// Task that receives and decodes RF signals
|
||||
static void rf_433_receiver_task(void* param) {
|
||||
esp_task_wdt_add(NULL);
|
||||
esp_log_level_set("rmt", ESP_LOG_NONE); // disable rmt messages about hw buffer too small
|
||||
esp_task_wdt_add(NULL);
|
||||
esp_log_level_set("rmt", ESP_LOG_NONE); // disable rmt messages about hw buffer too small
|
||||
const uint16_t tlow = (P_HIGH - P_LOW - (2 * P_MARGIN));
|
||||
const uint16_t thigh = (P_HIGH - P_LOW + (2 * P_MARGIN));
|
||||
|
||||
@@ -130,45 +127,38 @@ static void rf_433_receiver_task(void* param) {
|
||||
}
|
||||
}
|
||||
|
||||
// If we got a valid code, send it to processing task
|
||||
// If we got a valid code, process it
|
||||
if (code) {
|
||||
int64_t encoded = ((int64_t)len << 56) | code;
|
||||
int64_t encoded = ((int64_t)len << 56) | code;
|
||||
|
||||
ESP_LOGI(TAG, "GOT KEYCODE 0x%lx [%d]", (long) code, len);
|
||||
|
||||
if (learn_flag >= 0) {
|
||||
set_param_value_t(PARAM_KEYCODE_0 + learn_flag,
|
||||
(param_value_t){.i64 = encoded});
|
||||
ESP_LOGI(TAG, "LEARNED KEYCODE");
|
||||
learn_flag = -1;
|
||||
} else {
|
||||
rf_code_t rf_msg = {
|
||||
.code = code,
|
||||
.high_avg = high / 24,
|
||||
.low_avg = low / 24,
|
||||
.errors = err,
|
||||
.num_symbols = len
|
||||
};
|
||||
|
||||
// Don't do this anymore. No need to pass data between threads. Just act on it.
|
||||
// Non-blocking send - if queue is full, just drop it
|
||||
//xQueueSend(g_code_queue, &rf_msg, 0);
|
||||
|
||||
|
||||
for (uint8_t i = 0; i < NUM_RF_BUTTONS; i++) {
|
||||
int64_t match = get_param_value_t(PARAM_KEYCODE_0+i).i64;
|
||||
if (encoded == match) {
|
||||
switch (i) {
|
||||
case 0: pulseOverride(RELAY_A1); pulseOverride(RELAY_A3); break;
|
||||
case 1: pulseOverride(RELAY_B1); pulseOverride(RELAY_A3); break;
|
||||
case 2: pulseOverride(RELAY_A2); break;
|
||||
case 3: pulseOverride(RELAY_B2); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "GOT KEYCODE 0x%lx [%d]", (long) code, len);
|
||||
|
||||
if (learn_flag >= 0) {
|
||||
set_param_value_t(PARAM_KEYCODE_0 + learn_flag,
|
||||
(param_value_t){.i64 = encoded});
|
||||
ESP_LOGI(TAG, "LEARNED KEYCODE");
|
||||
learn_flag = -1;
|
||||
} else {
|
||||
rf_code_t rf_msg = {
|
||||
.code = code,
|
||||
.high_avg = high / 24,
|
||||
.low_avg = low / 24,
|
||||
.errors = err,
|
||||
.num_symbols = len
|
||||
};
|
||||
|
||||
for (uint8_t i = 0; i < NUM_RF_BUTTONS; i++) {
|
||||
int64_t match = get_param_value_t(PARAM_KEYCODE_0+i).i64;
|
||||
if (encoded == match) {
|
||||
switch (i) {
|
||||
case 0: pulseOverride(RELAY_A1); pulseOverride(RELAY_A3); break;
|
||||
case 1: pulseOverride(RELAY_B1); pulseOverride(RELAY_A3); break;
|
||||
case 2: pulseOverride(RELAY_A2); break;
|
||||
case 3: pulseOverride(RELAY_B2); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,11 +193,10 @@ static void rf_433_receiver_task(void* param) {
|
||||
}
|
||||
|
||||
// Start next receive
|
||||
|
||||
rmt_receive(rx_channel, symbols, sizeof(symbols), &rx_config);
|
||||
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
|
||||
// Cleanup (never reached in this case)
|
||||
@@ -217,52 +206,21 @@ static void rf_433_receiver_task(void* param) {
|
||||
}
|
||||
|
||||
esp_err_t rf_433_init() {
|
||||
g_code_queue = xQueueCreate(5, sizeof(rf_code_t));
|
||||
assert(g_code_queue);
|
||||
|
||||
xTaskCreate(rf_433_receiver_task, TAG, 4096, NULL, 10, NULL);
|
||||
|
||||
return ESP_OK;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rf_433_stop() { return ESP_OK; }
|
||||
|
||||
void rf_433_set_keycode(uint8_t index, int64_t code) {
|
||||
set_param_value_t(PARAM_KEYCODE_0+index, (param_value_t){.i64=code});
|
||||
set_param_value_t(PARAM_KEYCODE_0+index, (param_value_t){.i64=code});
|
||||
}
|
||||
|
||||
void rf_433_learn_keycode(uint8_t index) {
|
||||
if (index >= 8) return;
|
||||
learn_flag = index;
|
||||
if (index >= 8) return;
|
||||
learn_flag = index;
|
||||
}
|
||||
|
||||
void rf_433_cancel_learn_keycode() {
|
||||
learn_flag = -1;
|
||||
}
|
||||
|
||||
/*int8_t rf_433_get_keycode() {
|
||||
rf_code_t received_code;
|
||||
|
||||
if (xQueueReceive(g_code_queue, &received_code, 0) == pdPASS) {
|
||||
int64_t newcode = ((int64_t)received_code.num_symbols << 56) | received_code.code;
|
||||
|
||||
for (uint8_t i = 0; i < NUM_RF_BUTTONS; i++) {
|
||||
if (newcode == get_param_value_t(PARAM_KEYCODE_0+i).i64)
|
||||
return i;
|
||||
}
|
||||
ESP_LOGI("RF", "Received unknown code 0x%08lx (%d) [0x%16llx]", (unsigned long)received_code.code, received_code.num_symbols, (unsigned long long) newcode);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t rf_433_get_raw_keycode() {
|
||||
rf_code_t received_code;
|
||||
int64_t code = -1;
|
||||
if (xQueueReceive(g_code_queue, &received_code, 0) == pdPASS) {
|
||||
code = ((int64_t)received_code.num_symbols << 56) | received_code.code;
|
||||
//ESP_LOGI("RF", "Raw Code 0x%08lx (%d) [0x%16llx]", (unsigned long)received_code.code, received_code.num_symbols, (unsigned long long) code);
|
||||
}
|
||||
return code;
|
||||
}*/
|
||||
|
||||
void rf_433_clear_queue() {
|
||||
xQueueReset(g_code_queue);
|
||||
learn_flag = -1;
|
||||
}
|
||||
@@ -64,38 +64,39 @@ typedef enum {
|
||||
// ============================================================================
|
||||
|
||||
#define PARAM_LIST \
|
||||
PARAM_DEF(BOOT_TIME, i64, 0) \
|
||||
PARAM_DEF(NUM_MOVES, u32, 0) \
|
||||
PARAM_DEF(MOVE_START, u32, 0) \
|
||||
PARAM_DEF(MOVE_END, u32, 0) \
|
||||
PARAM_DEF(DRIVE_DIST, u16, 10) /*3*/\
|
||||
PARAM_DEF(DRIVE_DIST, u16, 10) /*4*/\
|
||||
PARAM_DEF(JACK_DIST, u8, 5) \
|
||||
PARAM_DEF(DRIVE_TPDF, u16, 4000) \
|
||||
PARAM_DEF(DRIVE_MSPF, u16, 600) \
|
||||
PARAM_DEF(JACK_MSPI, u16, 600) /*7*/\
|
||||
PARAM_DEF(JACK_MSPI, u16, 600) /*8*/\
|
||||
PARAM_DEF(KEYCODE_0, i64, 0x19000000005D0C61) \
|
||||
PARAM_DEF(KEYCODE_1, i64, 0x19000000005D0C62) \
|
||||
PARAM_DEF(KEYCODE_2, i64, 0x19000000005D0C64) \
|
||||
PARAM_DEF(KEYCODE_3, i64, 0x19000000005D0C68) /*11*/\
|
||||
PARAM_DEF(KEYCODE_3, i64, 0x19000000005D0C68) /*12*/\
|
||||
PARAM_DEF(KEYCODE_4, i64, -1) \
|
||||
PARAM_DEF(KEYCODE_5, i64, -1) \
|
||||
PARAM_DEF(KEYCODE_6, i64, -1) \
|
||||
PARAM_DEF(KEYCODE_7, i64, -1) /*15*/\
|
||||
PARAM_DEF(KEYCODE_7, i64, -1) /*16*/\
|
||||
PARAM_DEF(ADC_ALPHA_BATTERY, f32, 0.02) \
|
||||
PARAM_DEF(ADC_ALPHA_ISENS, f32, 0.02) \
|
||||
PARAM_DEF(ADC_ALPHA_IAZ, f32, 0.005) \
|
||||
PARAM_DEF(ADC_DB_IAZ, f32, 5.0) /*19*/\
|
||||
PARAM_DEF(ADC_DB_IAZ, f32, 5.0) /*20*/\
|
||||
PARAM_DEF(EFUSE_INOM_1, f32, 40.0) \
|
||||
PARAM_DEF(EFUSE_INOM_2, f32, 6.0) \
|
||||
PARAM_DEF(EFUSE_INOM_3, f32, 2.0) \
|
||||
PARAM_DEF(EFUSE_HEAT_THRESH, f32, 60.0) /*23*/\
|
||||
PARAM_DEF(EFUSE_HEAT_THRESH, f32, 60.0) /*24*/\
|
||||
PARAM_DEF(EFUSE_KINST, f32, 4.0) \
|
||||
PARAM_DEF(EFUSE_TAUCOOL, f32, 0.2) \
|
||||
PARAM_DEF(EFUSE_TCOOL, i64, 5000000) \
|
||||
PARAM_DEF(LOW_PROTECTION_V, f32, 10.0) /*27*/\
|
||||
PARAM_DEF(LOW_PROTECTION_V, f32, 10.0) /*28*/\
|
||||
PARAM_DEF(LOW_PROTECTION_S, i64, 10) \
|
||||
PARAM_DEF(CHG_LOW_V, f32, 5.0) \
|
||||
PARAM_DEF(CHG_LOW_S, i64, 5.0) \
|
||||
PARAM_DEF(CHG_BULK_S, i64, 20) /*31*/\
|
||||
PARAM_DEF(CHG_BULK_S, i64, 20) /*32*/\
|
||||
PARAM_DEF(RF_PULSE_LENGTH, u64, 350000) \
|
||||
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
<!doctype html><title>Control Panel</title><style>*{color:#eee;background-color:#111;font-family:sans-serif}input{text-align:right;box-sizing:border-box;background-color:#333;border:1px solid #666;width:100%;font-family:monospace}.changed{color:#111!important;background-color:#3d3!important}#commit_btn{color:#111;cursor:pointer;background-color:#3d3;border:none;width:100%;margin-top:10px;padding:10px;font-weight:700}#commit_btn[disabled]{color:#888;cursor:not-allowed;background-color:#444}table{border-collapse:collapse;width:100%}td{border-bottom:1px solid #222;padding:8px}tr:hover{background-color:#1a1a1a}</style></head><body><table id=table><tr><td>-</td><td>System Time</td><td><input id=in_time onchange=markChanged(this) step=1 type=datetime-local></td><td></td></tr><tr><td colspan=4><button disabled id=commit_btn onclick=commit_params()>Save Changes</button></td></tr></table><input accept=.bin id=firmware_file type=file><button id=upload_btn onclick=uploadFirmware()>Upload Firmware</button><script>let param_values=[];const param_names=[`Drive Distance`,`TPDF`,`Efuse Amt`,`Gain`,`Offset`],param_units=[`in`,`ft`,`in`,`V`,`ms`];function ge(x){return document.getElementById(x)}
|
||||
<!doctype html><title>Control Panel</title><style>*{color:#eee;background-color:#111;font-family:sans-serif}input{text-align:right;box-sizing:border-box;background-color:#333;border:1px solid #666;width:100%;font-family:monospace}.changed{color:#111!important;background-color:#3d3!important}#commit_btn{color:#111;cursor:pointer;background-color:#3d3;border:none;width:100%;margin-top:10px;padding:10px;font-weight:700}#commit_btn[disabled]{color:#888;cursor:not-allowed;background-color:#444}table{border-collapse:collapse;width:100%}td{border-bottom:1px solid #222;padding:8px}tr:hover{background-color:#1a1a1a}</style></head><body><table id=table><tr><td>-</td><td>System Time</td><td><input id=in_time onchange=markChanged(this) step=1 type=datetime-local></td><td></td></tr><tr><td colspan=4><button disabled id=commit_btn onclick=commit_params()>Save Changes</button></td></tr></table><table id=table2><tr><td>Firmware</td><td><input accept=.bin id=firmware_file type=file></td><td><button id=upload_btn onclick=uploadFirmware()>Upload Firmware</button></td><td></td></tr><tr><td>Log File</td><td><button id=log_btn onclick=downloadLogFile()>Download Log</button></td><td></td></tr></table><script>let param_values=[];const param_names=[`Drive Distance`,`TPDF`,`Efuse Amt`,`Gain`,`Offset`],param_units=[`in`,`ft`,`in`,`V`,`ms`];function ge(x){return document.getElementById(x)}
|
||||
// Highlight changed inputs and enable the save button
|
||||
function markChanged(el){el.classList.add(`changed`),ge(`commit_btn`).disabled=!1}
|
||||
// --- 1. GET DATA ---
|
||||
@@ -23,6 +23,6 @@ function commit_params(){ge(`commit_btn`).disabled=!0,document.querySelectorAll(
|
||||
// Time handling
|
||||
let epoch=Math.floor(new Date(input.value).getTime()/1e3);xhr.open(`POST`,`http://192.168.4.1/st`,!0),xhr.setRequestHeader(`Content-Type`,`application/json`),xhr.send(JSON.stringify({time:epoch})),input.classList.remove(`changed`)}else{
|
||||
// Parameter handling
|
||||
let id=input.id.split(`_`)[1],val=input.value.toLowerCase()===`null`?null:parseFloat(input.value);xhr.open(`POST`,`/sp`,!0),xhr.setRequestHeader(`Content-Type`,`application/json`),xhr.onload=function(){xhr.status===200&&input.classList.remove(`changed`)},xhr.send(JSON.stringify({id:parseInt(id),value:val}))}})}function uploadFirmware(){let fileInput=ge(`firmware_file`);if(!fileInput.files.length){alert(`No file selected`);return}let file=fileInput.files[0],xhr=new XMLHttpRequest;xhr.open(`POST`,`http://192.168.4.1/ota`,!0),xhr.setRequestHeader(`Content-Type`,`application/octet-stream`),xhr.onload=function(){xhr.status===200?alert(`Upload successful. Device may reboot.`):alert(`Upload failed: `+xhr.status)},xhr.onerror=function(){alert(`Network error during upload`)},xhr.send(file)}
|
||||
let id=input.id.split(`_`)[1],val=input.value.toLowerCase()===`null`?null:parseFloat(input.value);xhr.open(`POST`,`/sp`,!0),xhr.setRequestHeader(`Content-Type`,`application/json`),xhr.onload=function(){xhr.status===200&&input.classList.remove(`changed`)},xhr.send(JSON.stringify({id:parseInt(id),value:val}))}})}function uploadFirmware(){let fileInput=ge(`firmware_file`);if(!fileInput.files.length){alert(`No file selected`);return}let file=fileInput.files[0],xhr=new XMLHttpRequest;xhr.open(`POST`,`http://192.168.4.1/ota`,!0),xhr.setRequestHeader(`Content-Type`,`application/octet-stream`),xhr.onload=function(){xhr.status===200?alert(`Upload successful. Device may reboot.`):alert(`Upload failed: `+xhr.status)},xhr.onerror=function(){alert(`Network error during upload`)},xhr.send(file)}async function downloadLogFile(){try{let response=await fetch(`/log`);if(!response.ok)throw Error(`Network response was not ok`);let blob=await response.blob(),now=/* @__PURE__ */ new Date,formattedDate=`${String(now.getDate()).padStart(2,`0`)}${[`JAN`,`FEB`,`MAR`,`APR`,`MAY`,`JUN`,`JUL`,`AUG`,`SEP`,`OCT`,`NOV`,`DEC`][now.getMonth()]}${now.getFullYear()}-${String(now.getHours()).padStart(2,`0`)}${String(now.getMinutes()).padStart(2,`0`)}`,url=URL.createObjectURL(blob),a=document.createElement(`a`);a.href=url,a.download=`storage-${formattedDate}.bin`,document.body.appendChild(a),a.click(),document.body.removeChild(a),URL.revokeObjectURL(url)}catch(error){console.error(`Download failed:`,error)}}
|
||||
// Initial Load
|
||||
window.onload=fetchStatus;</script></body></html>
|
||||
@@ -29,6 +29,8 @@
|
||||
//#include "mdns.h"
|
||||
#include "webpage.h"
|
||||
|
||||
#include "esp_partition.h"
|
||||
|
||||
|
||||
#define HOSTNAME "sc.local"
|
||||
#define SOFT_AP_SSID "stockcropper"
|
||||
@@ -54,9 +56,39 @@ static esp_err_t root_get_handler(httpd_req_t *req) {
|
||||
|
||||
static esp_err_t log_get_handler(httpd_req_t *req) {
|
||||
ESP_LOGI(TAG, "log_get_handler");
|
||||
// Send the HTML response
|
||||
httpd_resp_set_type(req, "text/html");
|
||||
return httpd_resp_send(req, html_content, HTTPD_RESP_USE_STRLEN);
|
||||
|
||||
const esp_partition_t *storage_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
|
||||
if (storage_partition == NULL) {
|
||||
ESP_LOGE(TAG, "Storage partition not found");
|
||||
return httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Storage partition not found");
|
||||
}
|
||||
|
||||
size_t total_size = storage_partition->size;
|
||||
char len_str[16];
|
||||
sprintf(len_str, "%u", (unsigned)total_size);
|
||||
httpd_resp_set_type(req, "application/octet-stream");
|
||||
httpd_resp_set_hdr(req, "Content-Disposition", "attachment; filename=\"sc_storage.bin\"");
|
||||
httpd_resp_set_hdr(req, "Content-Length", len_str);
|
||||
|
||||
uint8_t buf[1024];
|
||||
size_t offset = 0;
|
||||
while (offset < total_size) {
|
||||
size_t to_read = MIN(sizeof(buf), total_size - offset);
|
||||
esp_err_t err = esp_partition_read(storage_partition, offset, buf, to_read);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read partition: %s", esp_err_to_name(err));
|
||||
return httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read storage");
|
||||
}
|
||||
if (httpd_resp_send_chunk(req, (const char *)buf, to_read) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send chunk");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
offset += to_read;
|
||||
}
|
||||
|
||||
// End chunked transfer
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// set time: timestamp (unix epoch, seconds)
|
||||
@@ -203,6 +235,8 @@ static esp_err_t ota_post_handler(httpd_req_t *req) {
|
||||
// Send response FIRST
|
||||
httpd_resp_send(req, "OTA update successful, rebooting...", HTTPD_RESP_USE_STRLEN);
|
||||
|
||||
set_param_value_t(PARAM_BOOT_TIME, (param_value_t){.i64 = system_rtc_get_raw_time()});
|
||||
|
||||
// THEN delay and reboot
|
||||
vTaskDelay(pdMS_TO_TICKS(2000)); // Give time for TCP to close properly
|
||||
esp_restart();
|
||||
|
||||
49
ota_deploy.bat
Normal file
49
ota_deploy.bat
Normal file
@@ -0,0 +1,49 @@
|
||||
@echo off
|
||||
REM ESP32 OTA Deployment Script for Windows
|
||||
|
||||
setlocal
|
||||
|
||||
REM Configuration
|
||||
set ESP32_IP=192.168.4.1
|
||||
set PROJECT_NAME=SC-F001
|
||||
set BUILD_DIR=build
|
||||
set BINARY_FILE=%BUILD_DIR%\%PROJECT_NAME%.bin
|
||||
|
||||
echo ========================================
|
||||
echo ESP32 OTA Deployment Script
|
||||
echo ========================================
|
||||
|
||||
|
||||
REM Step 1: Check if binary exists
|
||||
if not exist "%BINARY_FILE%" (
|
||||
echo Error: Binary file not found at %BINARY_FILE%
|
||||
echo Please update PROJECT_NAME in this script
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
for %%A in ("%BINARY_FILE%") do set BINARY_SIZE=%%~zA
|
||||
echo Binary size: %BINARY_SIZE% bytes
|
||||
|
||||
REM Step 2: Upload via OTA
|
||||
echo.
|
||||
echo [2/3] Uploading to ESP32 at %ESP32_IP%...
|
||||
|
||||
curl -X POST --data-binary @"%BINARY_FILE%" -w "HTTP Code: %%{http_code}\n" -o nul "http://%ESP32_IP%/ota"
|
||||
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Upload failed! Is the ESP32 reachable at %ESP32_IP%?
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Upload successful!
|
||||
echo ESP32 should be rebooting now...
|
||||
|
||||
REM Step 3: Wait for reboot
|
||||
echo.
|
||||
echo [3/3] Waiting for ESP32 to reboot...
|
||||
timeout /t 5 /nobreak > nul
|
||||
|
||||
echo Deployment complete!
|
||||
echo Check your device to verify it's running the new firmware.
|
||||
|
||||
exit /b 0
|
||||
Reference in New Issue
Block a user