feat: implement system time synchronization, web server handlers, and clock application components
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#include "web_server_pages.h"
|
||||
#include "web_server_pages.h"
|
||||
#include "sys_uart.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_http_server.h"
|
||||
@@ -227,7 +227,7 @@ static const char SERIAL_HTML[] =
|
||||
" }"
|
||||
"});"
|
||||
"log('[ABrobot Web Serial Connected on TX:GPIO21 / RX:GPIO20 (Internal Pull-Up Active)]\\n', 'log-sys');"
|
||||
"pollData();"
|
||||
"try{fetch('/time/sync?epoch='+Math.floor(Date.now()/1000));}catch(e){}pollData();"
|
||||
"</script></body></html>";
|
||||
|
||||
static esp_err_t serial_page_get(httpd_req_t *request)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "web_server_pages.h"
|
||||
#include "web_server_pages.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_wifi.h"
|
||||
@@ -91,7 +91,7 @@ static const char WIFI_HTML[] =
|
||||
" <label for=\"password\">Wi-Fi Password</label>"
|
||||
" <div class=\"pass-wrap\">"
|
||||
" <input type=\"password\" id=\"password\" name=\"password\" maxlength=\"64\" placeholder=\"Enter Wi-Fi password (WPA/WPA2)...\" required>"
|
||||
" <button type=\"button\" class=\"pass-toggle\" id=\"eyeBtn\" onclick=\"togglePassword()\" title=\"Show/Hide Password\">👁️</button>"
|
||||
" <button type=\"button\" class=\"pass-toggle\" id=\"eyeBtn\" onclick=\"togglePassword()\" title=\"Show/Hide Password\">ðŸ‘ï¸</button>"
|
||||
" </div>"
|
||||
" </div>"
|
||||
" <button type=\"submit\" class=\"primary\" id=\"btnConnect\">Connect to Network</button>"
|
||||
@@ -112,12 +112,12 @@ static const char WIFI_HTML[] =
|
||||
"const list=document.getElementById('networks'),manual=document.getElementById('manual'),manualBox=document.getElementById('manualBox'),hidden=document.getElementById('hidden'),passInput=document.getElementById('password'),msg=document.getElementById('statusMsg'),btnConnect=document.getElementById('btnConnect'),btnScan=document.getElementById('btnScan'),scanCount=document.getElementById('scanCount');"
|
||||
"function showMsg(text,type){msg.className='msg-box msg-'+(type||'info');msg.textContent=text;msg.style.display='block';}"
|
||||
"function toggleManual(){let on=hidden.checked;manualBox.style.display=on?'block':'none';manual.required=on;if(on){manual.value='';manual.focus();}else if(list.value)manual.value=list.value;}"
|
||||
"function togglePassword(){let isPass=passInput.type==='password';passInput.type=isPass?'text':'password';document.getElementById('eyeBtn').textContent=isPass?'🔒':'👁️';}"
|
||||
"function togglePassword(){let isPass=passInput.type==='password';passInput.type=isPass?'text':'password';document.getElementById('eyeBtn').textContent=isPass?'🔒':'ðŸ‘ï¸';}"
|
||||
"async function scan(){btnScan.disabled=true;btnScan.textContent='Scanning...';scanCount.textContent='Scanning...';showMsg('Scanning for 2.4 GHz Wi-Fi access points...','info');try{const res=await fetch('/scan');if(!res.ok)throw new Error('HTTP '+res.status);const data=await res.json();list.innerHTML='';if(!data.length){list.innerHTML='<option value=\"\">No networks found</option>';scanCount.textContent='0 APs';showMsg('No networks found. Check router or use manual SSID entry.','error');}else{data.forEach(n=>{const opt=document.createElement('option');opt.value=n.ssid;const qual=n.rssi>-60?'Strong':(n.rssi>-75?'Good':'Weak');opt.textContent=n.ssid+' ('+n.rssi+' dBm - '+qual+')';list.appendChild(opt);});scanCount.textContent=data.length+' APs';if(!hidden.checked)manual.value=list.value;showMsg('Found '+data.length+' Wi-Fi network(s). Select your network and enter credentials.','success');}}catch(e){scanCount.textContent='Error';showMsg('Wi-Fi scan failed: '+e.message,'error');}finally{btnScan.disabled=false;btnScan.textContent='Refresh';}}"
|
||||
"list.onchange=()=>{if(!hidden.checked)manual.value=list.value;};"
|
||||
"async function submitWifi(e){e.preventDefault();const ssidVal=manual.value.trim();const passVal=passInput.value;if(!ssidVal){showMsg('Please select or enter an SSID network name.','error');return;}btnConnect.disabled=true;btnConnect.textContent='Connecting...';showMsg('Saving credentials and connecting to \"'+ssidVal+'\"...','info');try{const body='ssid='+encodeURIComponent(ssidVal)+'&password='+encodeURIComponent(passVal);const res=await fetch('/configure',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:body});if(res.ok){showMsg('Credentials saved for \"'+ssidVal+'\". ESP32 is switching to Station mode. Please connect your device to \"'+ssidVal+'\".','success');}else{const err=await res.text();showMsg('Connection failed: '+err,'error');btnConnect.disabled=false;btnConnect.textContent='Connect to Network';}}catch(e){showMsg('Credentials saved for \"'+ssidVal+'\". ESP32 is connecting to Wi-Fi. Please connect to \"'+ssidVal+'\".','success');}}"
|
||||
"if(!hidden.checked&&list.value)manual.value=list.value;"
|
||||
"scan();"
|
||||
"try{fetch('/time/sync?epoch='+Math.floor(Date.now()/1000));}catch(e){}scan();"
|
||||
"</script></body></html>";
|
||||
|
||||
static void copy_string(uint8_t *destination, size_t size, const char *source)
|
||||
|
||||
@@ -1,11 +1,42 @@
|
||||
#include "web_server.h"
|
||||
#include "web_server.h"
|
||||
#include "web_server_pages.h"
|
||||
#include "sys_time.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_log.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
static const char *TAG = "SYS_WEB";
|
||||
static httpd_handle_t s_server;
|
||||
|
||||
static esp_err_t time_sync_handler(httpd_req_t *req)
|
||||
{
|
||||
char query[128] = {0};
|
||||
if (httpd_req_get_url_query_str(req, query, sizeof(query)) == ESP_OK) {
|
||||
char val[32] = {0};
|
||||
if (httpd_query_key_value(query, "epoch", val, sizeof(val)) == ESP_OK) {
|
||||
time_t epoch = (time_t)strtoull(val, NULL, 10);
|
||||
if (epoch >= 1704067200ULL) {
|
||||
sys_time_set_epoch(epoch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct tm tm_info;
|
||||
bool synced = sys_time_get_local(&tm_info);
|
||||
time_t now = sys_time_get_epoch();
|
||||
char strftime_buf[64];
|
||||
strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &tm_info);
|
||||
|
||||
char resp[160];
|
||||
snprintf(resp, sizeof(resp), "{\"synced\":%s,\"epoch\":%lld,\"time\":\"%s\",\"tz\":\"%s\"}",
|
||||
synced ? "true" : "false", (long long)now, strftime_buf, sys_time_get_timezone());
|
||||
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
return httpd_resp_sendstr(req, resp);
|
||||
}
|
||||
|
||||
esp_err_t web_server_start(void)
|
||||
{
|
||||
if (s_server) return ESP_OK;
|
||||
@@ -19,6 +50,14 @@ esp_err_t web_server_start(void)
|
||||
web_server_register_wifi_pages(s_server);
|
||||
web_server_register_ota_page(s_server);
|
||||
web_server_register_serial_pages(s_server);
|
||||
ESP_LOGI(TAG, "Web server started");
|
||||
|
||||
const httpd_uri_t time_uri = {
|
||||
.uri = "/time/sync",
|
||||
.method = HTTP_GET,
|
||||
.handler = time_sync_handler
|
||||
};
|
||||
httpd_register_uri_handler(s_server, &time_uri);
|
||||
|
||||
ESP_LOGI(TAG, "Web server started with real-time sync service");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user