STA모드 추가

This commit is contained in:
2026-02-18 15:49:30 +00:00
parent 9bb14219af
commit 0baac2bf90
9 changed files with 794 additions and 150 deletions

View File

@@ -194,18 +194,47 @@ tr:active{background:rgba(233,69,96,0.1);}
</div>
<div class="sgrp">
<h3>System Info</h3>
<div class="fr"><label>IP Address</label><input id="sIp" readonly></div>
<div class="fr"><label>RSSI</label><input id="sRssi" readonly></div>
<div class="fr"><label>AP IP</label><input id="sApIp" readonly></div>
<div class="fr"><label>AP Clients</label><input id="sApCli" readonly></div>
<div class="fr"><label>Free Heap</label><input id="sHeap" readonly></div>
<div class="fr"><label>Uptime</label><input id="sUp" readonly></div>
<button class="abtn" onclick="sendC('sysinfo')" style="background:var(--accent);">Refresh</button>
</div>
<div class="sgrp">
<h3>WiFi STA ( )</h3>
<div class="fr" style="flex-direction:row;align-items:center;gap:10px;">
<label>STA </label>
<label style="position:relative;display:inline-block;width:48px;height:26px;cursor:pointer;">
<input type="checkbox" id="staChk" style="opacity:0;width:0;height:0;" onchange="toggleSTA()">
<span style="position:absolute;inset:0;background:var(--border);border-radius:13px;transition:.3s;"></span>
<span id="staSlider" style="position:absolute;left:2px;top:2px;width:22px;height:22px;background:#fff;border-radius:50%;transition:.3s;"></span>
</label>
<span id="staLabel" style="font-size:12px;color:#888;">OFF</span>
</div>
<div id="staForm" style="display:none;">
<div class="fr"><label>SSID</label><input id="staSSID" type="text" placeholder="WiFi SSID" autocomplete="off"></div>
<div class="fr"><label>Password</label><input id="staPW" type="password" placeholder="WiFi Password" autocomplete="off"></div>
<button class="abtn" onclick="connectSTA()" id="staBtn" style="background:var(--ok);color:#000;">Connect</button>
</div>
<div id="staInfo" style="display:none;margin-top:6px;font-size:12px;">
<div class="fr"><label>STA Status</label><span id="staStatus" style="font-size:13px;">--</span></div>
<div class="fr"><label>STA IP</label><input id="staIpDisp" readonly style="font-size:12px;"></div>
<div class="fr"><label>RSSI</label><input id="staRssiDisp" readonly style="font-size:12px;"></div>
</div>
</div>
<div class="sgrp">
<h3>DS3231 RTC</h3>
<div class="fr"><label>RTC Status</label><span id="rtcSt" style="font-size:13px;color:#888;">--</span></div>
<div class="fr"><label>Time Synced</label><span id="rtcSynced" style="font-size:13px;">--</span></div>
<div class="fr"><label>Sync Count</label><span id="rtcSyncs" style="font-size:13px;color:#aaa;">0</span></div>
<div class="fr"><label>RTC Temp</label><span id="rtcTemp" style="font-size:13px;color:#aaa;">--</span></div>
</div>
<div class="sgrp">
<h3>SD Logging</h3>
<div class="fr"><label>Status</label><span id="logSt" style="color:var(--ok);font-size:13px;">Active</span></div>
<div class="fr"><label>Status</label><span id="logSt" style="color:var(--btn);font-size:13px;">Stopped</span></div>
<div class="fr"><label>Log File</label><input id="logFile" readonly style="font-size:11px;"></div>
<div style="display:flex;gap:8px;margin-top:6px;flex-wrap:wrap;">
<button class="abtn" onclick="sendC('toggle_log')" id="logBtn">Stop Logging</button>
<button class="abtn" onclick="sendC('toggle_log')" id="logBtn">Start Logging</button>
<button class="abtn" onclick="sendC('new_log')" style="background:var(--warn);color:#000;">New File</button>
</div>
</div>
@@ -233,8 +262,8 @@ tr:active{background:rgba(233,69,96,0.1);}
<!-- STATUS BAR -->
<div class="sbar">
<span class="ld rec" id="lDot"></span>
<span id="lInfo">Logging...</span>
<span class="ld" id="lDot"></span>
<span id="lInfo">Log OFF</span>
<span id="serInfo">115200 8N1</span>
<span id="rxC">RX:0</span>
<span id="txC">TX:0</span>
@@ -265,14 +294,14 @@ function wsConn(){
document.getElementById('wsDot').classList.add('on');
document.getElementById('wsSt').textContent='ON';
addSys('[Connected]');
// Send browser time to ESP32 for clock sync
// Send browser time to ESP32 for clock sync (silent - no terminal message)
let now=new Date();
let epoch=Math.floor(now.getTime()/1000);
let ms=now.getMilliseconds();
ws.send(JSON.stringify({cmd:'set_time',epoch:epoch,ms:ms}));
addSys('[Time sync: '+now.toLocaleString()+']');
sendC('sysinfo');
sendC('get_serial_config');
sendC('get_wifi');
};
ws.onmessage=function(e){
try{
@@ -281,7 +310,7 @@ function wsConn(){
else if(m.type==='sysinfo') updSys(m);
else if(m.type==='serial_config') updSer(m);
else if(m.type==='log_status') updLog(m);
else if(m.type==='time_synced'&&m.ok) addSys('[ESP32 time synced OK]');
else if(m.type==='wifi_status') updWifi(m);
}catch(x){}
};
ws.onclose=function(){
@@ -406,11 +435,86 @@ function updSer(m){
// ===== System Info =====
function updSys(m){
document.getElementById('sIp').value=m.ip||'';
document.getElementById('sRssi').value=(m.rssi||'')+' dBm';
document.getElementById('sApIp').value=m.apIp||'';
document.getElementById('sApCli').value=m.apClients||0;
document.getElementById('sHeap').value=fB(m.heap||0);
document.getElementById('sUp').value=fUp(m.uptime||0);
document.getElementById('tInfo').textContent=m.time||'--';
// STA info from sysinfo
if(m.staOn!==undefined) updWifi(m);
// RTC info
let rs=document.getElementById('rtcSt');
if(m.rtcOk){rs.textContent='OK (DS3231)';rs.style.color='var(--ok)';}
else{rs.textContent='Not found';rs.style.color='var(--btn)';}
let ry=document.getElementById('rtcSynced');
if(m.rtcSync){ry.textContent='Yes';ry.style.color='var(--ok)';}
else{ry.textContent='No';ry.style.color='var(--warn)';}
document.getElementById('rtcSyncs').textContent=m.rtcSyncs||0;
let t=m.rtcTemp;
document.getElementById('rtcTemp').textContent=(t&&t>-100)?(t.toFixed(1)+' °C'):'--';
}
// ===== WiFi STA Control =====
function updWifi(m){
let chk=document.getElementById('staChk');
let slider=document.getElementById('staSlider');
let label=document.getElementById('staLabel');
let form=document.getElementById('staForm');
let info=document.getElementById('staInfo');
chk.checked=m.staOn;
slider.style.transform=m.staOn?'translateX(22px)':'';
slider.parentElement.previousElementSibling.nextElementSibling.style.background=m.staOn?'var(--ok)':'var(--border)';
label.textContent=m.staOn?'ON':'OFF';
label.style.color=m.staOn?'var(--ok)':'#888';
form.style.display=m.staOn?'block':'none';
info.style.display=m.staOn?'block':'none';
if(m.staOn){
if(m.staSSID) document.getElementById('staSSID').value=m.staSSID;
let ss=document.getElementById('staStatus');
if(m.staConn){ss.textContent='Connected';ss.style.color='var(--ok)';}
else{ss.textContent='Disconnected';ss.style.color='var(--btn)';}
document.getElementById('staIpDisp').value=m.staIp||'--';
document.getElementById('staRssiDisp').value=m.staRssi?(m.staRssi+' dBm'):'--';
document.getElementById('staBtn').textContent='Disconnect';
document.getElementById('staBtn').style.background='var(--btn)';
document.getElementById('staBtn').style.color='#fff';
document.getElementById('staBtn').onclick=disconnectSTA;
}else{
document.getElementById('staBtn').textContent='Connect';
document.getElementById('staBtn').style.background='var(--ok)';
document.getElementById('staBtn').style.color='#000';
document.getElementById('staBtn').onclick=connectSTA;
}
}
function toggleSTA(){
let chk=document.getElementById('staChk');
let slider=document.getElementById('staSlider');
let form=document.getElementById('staForm');
let label=document.getElementById('staLabel');
slider.style.transform=chk.checked?'translateX(22px)':'';
slider.parentElement.previousElementSibling.nextElementSibling.style.background=chk.checked?'var(--ok)':'var(--border)';
label.textContent=chk.checked?'ON':'OFF';
label.style.color=chk.checked?'var(--ok)':'#888';
form.style.display=chk.checked?'block':'none';
if(!chk.checked) disconnectSTA();
}
function connectSTA(){
let ssid=document.getElementById('staSSID').value.trim();
let pw=document.getElementById('staPW').value;
if(!ssid){alert('SSID를 ');return;}
let ss=document.getElementById('staStatus');
if(ss) {ss.textContent='Connecting...';ss.style.color='var(--warn)';}
document.getElementById('staInfo').style.display='block';
if(ws&&ws.readyState===1) ws.send(JSON.stringify({cmd:'wifi_sta_on',ssid:ssid,pw:pw}));
}
function disconnectSTA(){
if(ws&&ws.readyState===1) ws.send(JSON.stringify({cmd:'wifi_sta_off'}));
document.getElementById('staInfo').style.display='none';
document.getElementById('staChk').checked=false;
toggleSTA();
}
// ===== Log Status =====