로드 부하 추가
This commit is contained in:
118
index.h
118
index.h
@@ -252,14 +252,14 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
|
||||
.status-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 10px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.status-card {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 15px;
|
||||
padding: 18px 12px;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
||||
@@ -270,15 +270,17 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
box-shadow: 0 6px 20px rgba(0,0,0,0.3);
|
||||
}
|
||||
.status-card h3 {
|
||||
font-size: 0.75em;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 8px;
|
||||
letter-spacing: 1px;
|
||||
font-size: 0.8em;
|
||||
opacity: 0.95;
|
||||
margin-bottom: 10px;
|
||||
letter-spacing: 0.5px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-card .value {
|
||||
font-size: 1.5em;
|
||||
font-size: 1.6em;
|
||||
font-weight: 700;
|
||||
font-family: 'Courier New', monospace;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.status-card.status-on {
|
||||
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
|
||||
@@ -288,6 +290,41 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* 버스 부하율 색상 */
|
||||
.status-card.bus-load-low {
|
||||
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
|
||||
}
|
||||
.status-card.bus-load-medium {
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
}
|
||||
.status-card.bus-load-high {
|
||||
background: linear-gradient(135deg, #eb3349 0%, #f45c43 100%);
|
||||
}
|
||||
|
||||
/* 반응형: 모바일 */
|
||||
@media (max-width: 768px) {
|
||||
.status-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
.status-card {
|
||||
padding: 15px 10px;
|
||||
}
|
||||
.status-card h3 {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
.status-card .value {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
}
|
||||
|
||||
/* 반응형: 대형 화면 */
|
||||
@media (min-width: 1200px) {
|
||||
.status-grid {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #333;
|
||||
margin: 20px 0 10px 0;
|
||||
@@ -339,7 +376,7 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white; /* ⭐ #666 → white */
|
||||
color: white;
|
||||
}
|
||||
.control-row button:hover {
|
||||
transform: translateY(-2px);
|
||||
@@ -855,7 +892,7 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
</div>
|
||||
<div class="time-info-item">
|
||||
<div class="time-label">CONNECTION</div>
|
||||
<div class="time-value" id="sync-status">연결 중...</div>
|
||||
<div class="time-value" id="sync-status">Connecting...</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-time-sync" onclick="syncTimeFromPhone()">📱 Sync from Phone</button>
|
||||
@@ -906,6 +943,10 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
<h3>SPEED</h3>
|
||||
<div class="value" id="msg-speed">0/s</div>
|
||||
</div>
|
||||
<div class="status-card" id="bus-load-card">
|
||||
<h3>BUS LOAD</h3>
|
||||
<div class="value" id="bus-load">0%</div>
|
||||
</div>
|
||||
<div class="status-card status-off" id="time-sync-card">
|
||||
<h3>TIME SYNC</h3>
|
||||
<div class="value" id="sync-count">0</div>
|
||||
@@ -971,14 +1012,14 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
<span class="format-info">(Text - Excel Ready)</span>
|
||||
</label>
|
||||
</div>
|
||||
<button onclick="saveFileFormat()" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 8px 16px;">💾 Save</button>
|
||||
<button onclick="saveFileFormat()">💾 Save</button>
|
||||
<span id="format-save-status" style="color: #11998e; font-size: 0.85em; font-weight: 600;"></span>
|
||||
</div>
|
||||
<div class="control-row">
|
||||
<button onclick="startLogging()" style="background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);">Start Logging</button>
|
||||
<button onclick="stopLogging()" style="background: linear-gradient(135deg, #eb3349 0%, #f45c43 100%);">Stop Logging</button>
|
||||
<button onclick="hardwareReset()" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); color: white;">🔄 Hardware Reset</button>
|
||||
<button onclick="clearMessages()">Clear Display</button>
|
||||
<button onclick="startLogging()">▶ Start Logging</button>
|
||||
<button onclick="stopLogging()">⏹ Stop Logging</button>
|
||||
<button onclick="hardwareReset()">🔄 Hardware Reset</button>
|
||||
<button onclick="clearMessages()">🗑 Clear Display</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1105,7 +1146,7 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
<th>DLC</th>
|
||||
<th>Data</th>
|
||||
<th>Count</th>
|
||||
<th>Time(ms)</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="can-messages"></tbody>
|
||||
@@ -1164,8 +1205,24 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
|
||||
function updateCurrentTime() {
|
||||
const now = new Date();
|
||||
const timeStr = now.toLocaleTimeString('ko-KR', {hour12: false});
|
||||
document.getElementById('current-time').textContent = timeStr;
|
||||
const h = String(now.getHours()).padStart(2, '0');
|
||||
const m = String(now.getMinutes()).padStart(2, '0');
|
||||
const s = String(now.getSeconds()).padStart(2, '0');
|
||||
document.getElementById('current-time').textContent = `${h}h ${m}m ${s}s`;
|
||||
}
|
||||
|
||||
// CAN 메시지 시간 포맷 함수 (초.밀리초 형식으로 간결하게)
|
||||
function formatTimestamp(ms) {
|
||||
const totalSeconds = ms / 1000;
|
||||
|
||||
// 1초 미만: 0.xxx s
|
||||
if (ms < 1000) {
|
||||
return `${totalSeconds.toFixed(3)} s`;
|
||||
}
|
||||
// 1초 이상: xxx.xxx s (소수점 3자리)
|
||||
else {
|
||||
return `${totalSeconds.toFixed(3)} s`;
|
||||
}
|
||||
}
|
||||
setInterval(updateCurrentTime, 1000);
|
||||
updateCurrentTime();
|
||||
@@ -1217,7 +1274,7 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
|
||||
ws.onopen = function() {
|
||||
console.log('WebSocket connected');
|
||||
document.getElementById('sync-status').textContent = '연결됨';
|
||||
document.getElementById('sync-status').textContent = 'Connected';
|
||||
document.getElementById('sync-status').style.color = '#38ef7d';
|
||||
|
||||
// ⭐⭐⭐ 자동 시간 동기화 (페이지 로드 시 항상 실행)
|
||||
@@ -1238,7 +1295,7 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
|
||||
ws.onclose = function() {
|
||||
console.log('WebSocket disconnected');
|
||||
document.getElementById('sync-status').textContent = '연결 끊김';
|
||||
document.getElementById('sync-status').textContent = 'Disconnected';
|
||||
document.getElementById('sync-status').style.color = '#f45c43';
|
||||
mcpModeSynced = false; // 🆕 재연결 시 다시 동기화하도록 플래그 리셋
|
||||
window.canFormatSynced = false; // 🆕 File Format도 재동기화
|
||||
@@ -1422,6 +1479,23 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
document.getElementById('msg-speed').textContent = data.msgPerSec + '/s';
|
||||
}
|
||||
|
||||
// 🆕 버스 부하율 업데이트
|
||||
if (data.busLoad !== undefined) {
|
||||
const busLoadCard = document.getElementById('bus-load-card');
|
||||
const busLoadValue = document.getElementById('bus-load');
|
||||
busLoadValue.textContent = data.busLoad + '%';
|
||||
|
||||
// 색상 변경 (부하율에 따라)
|
||||
busLoadCard.classList.remove('bus-load-low', 'bus-load-medium', 'bus-load-high');
|
||||
if (data.busLoad < 50) {
|
||||
busLoadCard.classList.add('bus-load-low');
|
||||
} else if (data.busLoad < 80) {
|
||||
busLoadCard.classList.add('bus-load-medium');
|
||||
} else {
|
||||
busLoadCard.classList.add('bus-load-high');
|
||||
}
|
||||
}
|
||||
|
||||
// 시간 동기화 - ★ 수정: timeSync 또는 timeSynced 둘 다 지원
|
||||
const timeSyncCard = document.getElementById('time-sync-card');
|
||||
const timeSynced = data.timeSynced !== undefined ? data.timeSynced : data.timeSync;
|
||||
@@ -1612,7 +1686,7 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
row.cells[1].textContent = msg.dlc;
|
||||
row.cells[2].textContent = msg.data;
|
||||
row.cells[3].textContent = msg.updateCount;
|
||||
row.cells[4].textContent = msg.timestamp;
|
||||
row.cells[4].textContent = formatTimestamp(msg.timestamp);
|
||||
|
||||
if (hasChanged) {
|
||||
row.classList.add('flash-row');
|
||||
@@ -1626,7 +1700,7 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
'<td>' + msg.dlc + '</td>' +
|
||||
'<td class="mono">' + msg.data + '</td>' +
|
||||
'<td>' + msg.updateCount + '</td>' +
|
||||
'<td>' + msg.timestamp + '</td>';
|
||||
'<td>' + formatTimestamp(msg.timestamp) + '</td>';
|
||||
row.classList.add('flash-row');
|
||||
setTimeout(() => row.classList.remove('flash-row'), 300);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user