add config period

Signed-off-by: YoungSoo Shin <shinys000114@gmail.com>
This commit is contained in:
2025-12-09 14:23:27 +09:00
parent a75ec53d23
commit a1255e8304
10 changed files with 100 additions and 6 deletions

View File

@@ -44,6 +44,7 @@ enum nconfig_type
USB_CURRENT_LIMIT, ///< The maximum current limit for the USB out. USB_CURRENT_LIMIT, ///< The maximum current limit for the USB out.
PAGE_USERNAME, ///< Webpage username PAGE_USERNAME, ///< Webpage username
PAGE_PASSWORD, ///< Webpage password PAGE_PASSWORD, ///< Webpage password
SENSOR_PERIOD_MS, ///< Sensor period
NCONFIG_TYPE_MAX, ///< Sentinel for the maximum number of configuration types. NCONFIG_TYPE_MAX, ///< Sentinel for the maximum number of configuration types.
}; };

View File

@@ -30,6 +30,7 @@ const static char* keys[NCONFIG_TYPE_MAX] = {
[USB_CURRENT_LIMIT] = "usb_climit", [USB_CURRENT_LIMIT] = "usb_climit",
[PAGE_USERNAME] = "username", [PAGE_USERNAME] = "username",
[PAGE_PASSWORD] = "password", [PAGE_PASSWORD] = "password",
[SENSOR_PERIOD_MS] = "sensor_period",
}; };
struct default_value struct default_value
@@ -54,6 +55,7 @@ struct default_value const default_values[] = {
{USB_CURRENT_LIMIT, "3.0"}, {USB_CURRENT_LIMIT, "3.0"},
{PAGE_USERNAME, "admin"}, {PAGE_USERNAME, "admin"},
{PAGE_PASSWORD, "password"}, {PAGE_PASSWORD, "password"},
{SENSOR_PERIOD_MS, "1000"},
}; };
esp_err_t init_nconfig() esp_err_t init_nconfig()

View File

@@ -289,6 +289,25 @@ void init_status_monitor()
xTaskCreate(shutdown_load_sw_task, "shutdown_sw_task", configMINIMAL_STACK_SIZE * 3, NULL, 15, xTaskCreate(shutdown_load_sw_task, "shutdown_sw_task", configMINIMAL_STACK_SIZE * 3, NULL, 15,
&shutdown_task_handle); &shutdown_task_handle);
ESP_ERROR_CHECK(esp_timer_start_periodic(sensor_timer, 1000000)); nconfig_read(SENSOR_PERIOD_MS, buf, sizeof(buf));
ESP_ERROR_CHECK(esp_timer_start_periodic(sensor_timer, strtol(buf, NULL, 10) * 1000));
ESP_ERROR_CHECK(esp_timer_start_periodic(wifi_status_timer, 1000000 * 5)); ESP_ERROR_CHECK(esp_timer_start_periodic(wifi_status_timer, 1000000 * 5));
} }
esp_err_t update_sensor_period(int period)
{
if (period < 500 || period > 10000) // 0.5 sec ~ 10 sec
{
return ESP_ERR_INVALID_ARG;
}
char buf[10];
sprintf(buf, "%d", period);
esp_err_t err = nconfig_write(SENSOR_PERIOD_MS, buf);
if (err != ESP_OK) {
return err;
}
esp_timer_stop(sensor_timer);
return esp_timer_start_periodic(sensor_timer, period * 1000);
}

View File

@@ -20,5 +20,6 @@ typedef struct
} sensor_data_t; } sensor_data_t;
void init_status_monitor(); void init_status_monitor();
esp_err_t update_sensor_period(int period);
#endif // ODROID_REMOTE_HTTP_MONITOR_H #endif // ODROID_REMOTE_HTTP_MONITOR_H

View File

@@ -6,6 +6,7 @@
#include "esp_log.h" #include "esp_log.h"
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_timer.h" #include "esp_timer.h"
#include "monitor.h"
#include "nconfig.h" #include "nconfig.h"
#include "webserver.h" #include "webserver.h"
#include "wifi.h" #include "wifi.h"
@@ -47,6 +48,11 @@ static esp_err_t setting_get_handler(httpd_req_t* req)
cJSON_AddStringToObject(root, "baudrate", buf); cJSON_AddStringToObject(root, "baudrate", buf);
} }
if (nconfig_read(SENSOR_PERIOD_MS, buf, sizeof(buf)) == ESP_OK)
{
cJSON_AddStringToObject(root, "period", buf);
}
// Add current limits to the response // Add current limits to the response
if (nconfig_read(VIN_CURRENT_LIMIT, buf, sizeof(buf)) == ESP_OK) if (nconfig_read(VIN_CURRENT_LIMIT, buf, sizeof(buf)) == ESP_OK)
{ {
@@ -174,6 +180,7 @@ static esp_err_t setting_post_handler(httpd_req_t* req)
cJSON* net_type_item = cJSON_GetObjectItem(root, "net_type"); cJSON* net_type_item = cJSON_GetObjectItem(root, "net_type");
cJSON* ssid_item = cJSON_GetObjectItem(root, "ssid"); cJSON* ssid_item = cJSON_GetObjectItem(root, "ssid");
cJSON* baud_item = cJSON_GetObjectItem(root, "baudrate"); cJSON* baud_item = cJSON_GetObjectItem(root, "baudrate");
cJSON* period_item = cJSON_GetObjectItem(root, "period");
cJSON* vin_climit_item = cJSON_GetObjectItem(root, "vin_current_limit"); cJSON* vin_climit_item = cJSON_GetObjectItem(root, "vin_current_limit");
cJSON* main_climit_item = cJSON_GetObjectItem(root, "main_current_limit"); cJSON* main_climit_item = cJSON_GetObjectItem(root, "main_current_limit");
cJSON* usb_climit_item = cJSON_GetObjectItem(root, "usb_current_limit"); cJSON* usb_climit_item = cJSON_GetObjectItem(root, "usb_current_limit");
@@ -289,6 +296,13 @@ static esp_err_t setting_post_handler(httpd_req_t* req)
change_baud_rate(strtol(baudrate, NULL, 10)); change_baud_rate(strtol(baudrate, NULL, 10));
httpd_resp_sendstr(req, "{\"status\":\"baudrate_updated\"}"); httpd_resp_sendstr(req, "{\"status\":\"baudrate_updated\"}");
} }
else if (period_item && cJSON_IsString(period_item))
{
const char* period_str = period_item->valuestring;
ESP_LOGI(TAG, "Received period set request: %s", period_str);
update_sensor_period(strtol(period_str, NULL, 10));
httpd_resp_sendstr(req, "{\"status\":\"period_updated\"}");
}
else if (vin_climit_item || main_climit_item || usb_climit_item) else if (vin_climit_item || main_climit_item || usb_climit_item)
{ {
char num_buf[10]; char num_buf[10];

View File

@@ -359,7 +359,7 @@
</form> </form>
</div> </div>
<div class="tab-pane fade" id="device-settings-pane" role="tabpanel"> <div class="tab-pane fade" id="device-settings-pane" role="tabpanel">
<div class="mb-3"> <div class="mb-3 p-3 border rounded">
<label for="baud-rate-select" class="form-label">UART Baud Rate</label> <label for="baud-rate-select" class="form-label">UART Baud Rate</label>
<select class="form-select" id="baud-rate-select"> <select class="form-select" id="baud-rate-select">
<option value="9600">9600</option> <option value="9600">9600</option>
@@ -372,6 +372,16 @@
<option value="921600">921600</option> <option value="921600">921600</option>
<option value="1500000" selected>1500000</option> <option value="1500000" selected>1500000</option>
</select> </select>
<div class="d-flex justify-content-end mt-2">
<button type="button" class="btn btn-primary btn-sm" id="baud-rate-apply-button">Apply</button>
</div>
</div>
<div class="mb-3 p-3 border rounded">
<label for="period-slider" class="form-label">Sensor Period: <span class="fw-bold text-primary" id="period-value">...</span> ms</label>
<input type="range" class="form-range" id="period-slider" min="500" max="5000" step="100">
<div class="d-flex justify-content-end mt-2">
<button type="button" class="btn btn-primary btn-sm" id="period-apply-button">Apply</button>
</div>
</div> </div>
<hr> <hr>
<div class="mb-3"> <div class="mb-3">
@@ -380,7 +390,6 @@
<button type="button" class="btn btn-danger" id="reboot-button">Reboot Now</button> <button type="button" class="btn btn-danger" id="reboot-button">Reboot Now</button>
</div> </div>
<div class="d-flex justify-content-end pt-3 border-top mt-3"> <div class="d-flex justify-content-end pt-3 border-top mt-3">
<button type="button" class="btn btn-primary me-2" id="baud-rate-apply-button">Apply</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div> </div>
</div> </div>

View File

@@ -104,7 +104,6 @@ export async function postNetworkSettings(payload) {
* Posts the selected UART baud rate to the server. * Posts the selected UART baud rate to the server.
* @param {string} baudrate The selected baud rate. * @param {string} baudrate The selected baud rate.
* @returns {Promise<Response>} A promise that resolves to the raw fetch response. * @returns {Promise<Response>} A promise that resolves to the raw fetch response.
* @throws {Error} Throws an error if the request fails.
*/ */
export async function postBaudRateSetting(baudrate) { export async function postBaudRateSetting(baudrate) {
const response = await fetch('/api/setting', { const response = await fetch('/api/setting', {
@@ -113,7 +112,24 @@ export async function postBaudRateSetting(baudrate) {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
...getAuthHeaders(), ...getAuthHeaders(),
}, },
body: JSON.stringify({baudrate}), body: JSON.stringify({ baudrate }),
});
return await handleResponse(response);
}
/**
* Posts the selected sensor period to the server.
* @param {string} period The selected period in milliseconds.
* @returns {Promise<Response>} A promise that resolves to the raw fetch response.
*/
export async function postPeriodSetting(period) {
const response = await fetch('/api/setting', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...getAuthHeaders(),
},
body: JSON.stringify({ period }),
}); });
return await handleResponse(response); return await handleResponse(response);
} }

View File

@@ -76,6 +76,9 @@ export const apPasswordInput = document.getElementById('ap-password');
// --- Device Settings Elements --- // --- Device Settings Elements ---
export const baudRateSelect = document.getElementById('baud-rate-select'); export const baudRateSelect = document.getElementById('baud-rate-select');
export const baudRateApplyButton = document.getElementById('baud-rate-apply-button'); export const baudRateApplyButton = document.getElementById('baud-rate-apply-button');
export const periodSlider = document.getElementById('period-slider');
export const periodValue = document.getElementById('period-value');
export const periodApplyButton = document.getElementById('period-apply-button');
export const rebootButton = document.getElementById('reboot-button'); export const rebootButton = document.getElementById('reboot-button');
// --- Current Limit Settings Elements --- // --- Current Limit Settings Elements ---

View File

@@ -77,8 +77,9 @@ export function setupEventListeners() {
dom.networkApplyButton.addEventListener('click', ui.applyNetworkSettings); dom.networkApplyButton.addEventListener('click', ui.applyNetworkSettings);
dom.apModeApplyButton.addEventListener('click', ui.applyApModeSettings); dom.apModeApplyButton.addEventListener('click', ui.applyApModeSettings);
dom.baudRateApplyButton.addEventListener('click', ui.applyBaudRateSettings); dom.baudRateApplyButton.addEventListener('click', ui.applyBaudRateSettings);
dom.periodApplyButton.addEventListener('click', ui.applyPeriodSettings);
// --- Device Settings (Reboot) --- // --- Device Settings (Reboot & Period Slider) ---
if (dom.rebootButton) { if (dom.rebootButton) {
dom.rebootButton.addEventListener('click', () => { dom.rebootButton.addEventListener('click', () => {
if (confirm('Are you sure you want to reboot the device?')) { if (confirm('Are you sure you want to reboot the device?')) {
@@ -101,6 +102,12 @@ export function setupEventListeners() {
}); });
} }
if (dom.periodSlider) {
dom.periodSlider.addEventListener('input', () => {
dom.periodValue.textContent = dom.periodSlider.value;
});
}
// --- Current Limit Settings --- // --- Current Limit Settings ---
dom.vinSlider.addEventListener('input', () => updateSliderValue(dom.vinSlider, dom.vinValueSpan)); dom.vinSlider.addEventListener('input', () => updateSliderValue(dom.vinSlider, dom.vinValueSpan));
dom.mainSlider.addEventListener('input', () => updateSliderValue(dom.mainSlider, dom.mainValueSpan)); dom.mainSlider.addEventListener('input', () => updateSliderValue(dom.mainSlider, dom.mainValueSpan));

View File

@@ -301,6 +301,24 @@ export async function applyBaudRateSettings() {
} }
} }
/**
* Applies the selected sensor period by sending it to the server.
*/
export async function applyPeriodSettings() {
const period = dom.periodSlider.value;
dom.periodApplyButton.disabled = true;
dom.periodApplyButton.innerHTML = `<span class="spinner-border spinner-border-sm" aria-hidden="true"></span> Applying...`;
try {
await api.postPeriodSetting(period);
} catch (error) {
console.error('Error applying period:', error);
} finally {
dom.periodApplyButton.disabled = false;
dom.periodApplyButton.innerHTML = 'Apply';
}
}
/** /**
* Fetches and displays the current network and device settings in the settings modal. * Fetches and displays the current network and device settings in the settings modal.
*/ */
@@ -338,6 +356,10 @@ export async function initializeSettings() {
if (data.baudrate) { if (data.baudrate) {
dom.baudRateSelect.value = data.baudrate; dom.baudRateSelect.value = data.baudrate;
} }
if (data.period) {
dom.periodSlider.value = data.period;
dom.periodValue.textContent = data.period;
}
} catch (error) { } catch (error) {
console.error('Error initializing settings:', error); console.error('Error initializing settings:', error);