diff --git a/ESP32_CAN_Logger-a.ino b/ESP32_CAN_Logger-a.ino
index 21c3c55..97b6921 100644
--- a/ESP32_CAN_Logger-a.ino
+++ b/ESP32_CAN_Logger-a.ino
@@ -2960,6 +2960,27 @@ void webUpdateTask(void *parameter) {
doc["sdReady"] = sdCardReady;
doc["totalMsg"] = totalMsgCount;
doc["msgPerSec"] = msgPerSecond;
+
+ // π CAN λ²μ€ λΆνμ¨ κ³μ°
+ // CAN μλλ³ μ΄λ‘ μ μ΅λ λ©μμ§/μ΄ (8λ°μ΄νΈ λ°μ΄ν° κΈ°μ€)
+ // 125 Kbps: ~1,000 msg/s
+ // 250 Kbps: ~2,000 msg/s
+ // 500 Kbps: ~4,000 msg/s
+ // 1 Mbps: ~8,000 msg/s
+ uint32_t maxMsgPerSec;
+ switch(currentCanSpeed) {
+ case CAN_125KBPS: maxMsgPerSec = 1000; break;
+ case CAN_250KBPS: maxMsgPerSec = 2000; break;
+ case CAN_500KBPS: maxMsgPerSec = 4000; break;
+ case CAN_1000KBPS:
+ default: maxMsgPerSec = 8000; break;
+ }
+
+ // λΆνμ¨ κ³μ° (0~100%)
+ float busLoad = (msgPerSecond * 100.0) / maxMsgPerSec;
+ if (busLoad > 100.0) busLoad = 100.0;
+ doc["busLoad"] = (int)busLoad; // μ μλ‘ μ μ‘
+
doc["totalTx"] = totalTxCount;
doc["totalSerialRx"] = totalSerialRxCount;
doc["totalSerialTx"] = totalSerialTxCount;
diff --git a/index.h b/index.h
index 336c7a6..517e617 100644
--- a/index.h
+++ b/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(
CONNECTION
-
μ°κ²° μ€...
+
Connecting...
@@ -906,6 +943,10 @@ const char index_html[] PROGMEM = R"rawliteral(
SPEED
0/s
+
TIME SYNC
0
@@ -971,14 +1012,14 @@ const char index_html[] PROGMEM = R"rawliteral(
(Text - Excel Ready)
-
+
-
-
-
-
+
+
+
+
@@ -1105,7 +1146,7 @@ const char index_html[] PROGMEM = R"rawliteral(
DLC |
Data |
Count |
- Time(ms) |
+ Time |
@@ -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(
'' + msg.dlc + ' | ' +
'' + msg.data + ' | ' +
'' + msg.updateCount + ' | ' +
- '' + msg.timestamp + ' | ';
+ '' + formatTimestamp(msg.timestamp) + ' | ';
row.classList.add('flash-row');
setTimeout(() => row.classList.remove('flash-row'), 300);
}