Skip to content

Commit a54e91b

Browse files
committed
fix: webapp ntp set
1 parent 6048f60 commit a54e91b

File tree

4 files changed

+83
-11
lines changed

4 files changed

+83
-11
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ SmartClimate uses a custom partition table tailored for persistent storage, appl
9090
- [x] Uptime tracking (seconds to days format)
9191
- [x] Lightweight JSON API for system status and configuration
9292
- [x] Graphical user interface built with LVGL
93+
- [x] NTP-based time synchronization
9394

9495
## Roadmap
9596

96-
- [ ] NTP-based time synchronization
9797
- [ ] UI theming & styling system
9898
- [ ] Internationalization (i18n) support
9999
- [ ] Better error feedback on failed Wi-Fi connection

main/webserver/html/css/style.css

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,22 @@ main {
6767
flex-direction: column;
6868
}
6969

70+
input {
71+
width: 100%;
72+
padding: 8px;
73+
border: 2px solid var(--border-color);
74+
border-radius: 6px;
75+
background-color: var(--container-bg);
76+
color: var(--text-color);
77+
font-size: 1rem;
78+
margin-bottom: 10px;
79+
}
80+
81+
input::placeholder {
82+
color: rgba(255, 255, 255, 0.6);
83+
font-style: italic;
84+
}
85+
7086
button {
7187
padding: 0.8rem 1.2rem;
7288
font-size: 1rem;
@@ -116,10 +132,10 @@ button:active {
116132

117133
.loader {
118134
display: none;
119-
width: 40px;
120-
height: 40px;
121-
border: 4px solid rgba(255, 255, 255, 0.3);
122-
border-top: 4px solid var(--accent-color);
135+
width: 30px;
136+
height: 30px;
137+
border: 3px solid rgba(255, 255, 255, 0.3);
138+
border-top: 3px solid var(--accent-color);
123139
border-radius: 50%;
124140
animation: spin 0.8s linear infinite;
125141
margin: 1rem auto;

main/webserver/html/index.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ <h2>Wi-Fi Management</h2>
2727
<div id="wifi-loader" class="loader"></div>
2828
<div id="wifi-output" class="output-container"></div>
2929
</section>
30+
31+
<section id="ntp-section" class="container">
32+
<h2>NTP Provider</h2>
33+
<label for="ntp-input">NTP Server:</label>
34+
<input type="text" id="ntp-input" placeholder="ex: pool.ntp.org" />
35+
<button id="ntp-set-btn">Set NTP Server</button>
36+
<div id="ntp-loader" class="loader"></div>
37+
<div id="ntp-output" class="output-container"></div>
38+
</section>
3039
</div>
3140
</main>
3241

main/webserver/html/js/main.js

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ document.addEventListener("DOMContentLoaded", () => {
66
const wifiOutput = document.getElementById("wifi-output");
77
const statusLoader = document.getElementById("status-loader");
88
const wifiLoader = document.getElementById("wifi-loader");
9+
const ntpInput = document.getElementById("ntp-input");
10+
const ntpOutput = document.getElementById("ntp-output");
11+
const ntpLoader = document.getElementById("ntp-loader");
12+
const ntpSetBtn = document.getElementById("ntp-set-btn");
913

1014
const showLoader = (loader) => {
1115
loader.style.display = "block";
@@ -15,6 +19,18 @@ document.addEventListener("DOMContentLoaded", () => {
1519
loader.style.display = "none";
1620
};
1721

22+
const disableButton = (button) => {
23+
button.disabled = true;
24+
button.style.opacity = "0.6";
25+
button.innerText = "Loading...";
26+
};
27+
28+
const enableButton = (button, originalText) => {
29+
button.disabled = false;
30+
button.style.opacity = "1";
31+
button.innerText = originalText;
32+
};
33+
1834
const showOutput = (section, html, loader) => {
1935
hideLoader(loader);
2036
section.innerHTML = html;
@@ -23,9 +39,7 @@ document.addEventListener("DOMContentLoaded", () => {
2339
const handleApi = (url, formatter, outputSection, button, loader) => {
2440
showLoader(loader);
2541
outputSection.innerHTML = "";
26-
button.disabled = true;
27-
button.style.opacity = "0.6";
28-
button.innerText = "Loading...";
42+
disableButton(button);
2943

3044
fetch(url)
3145
.then((res) => res.json())
@@ -44,9 +58,7 @@ document.addEventListener("DOMContentLoaded", () => {
4458
})
4559
.finally(() => {
4660
hideLoader(loader);
47-
button.disabled = false;
48-
button.style.opacity = "1";
49-
button.innerText = button.dataset.originalText;
61+
enableButton(button, button.dataset.originalText);
5062
});
5163
};
5264

@@ -95,6 +107,38 @@ document.addEventListener("DOMContentLoaded", () => {
95107
`;
96108
};
97109

110+
const handleNtpUpdate = () => {
111+
const ntpDomain = ntpInput.value.trim();
112+
if (!ntpDomain) {
113+
ntpOutput.innerHTML = `<p style="color: var(--error-color);">⚠️ Please enter an NTP server domain.</p>`;
114+
return;
115+
}
116+
117+
disableButton(ntpSetBtn);
118+
showLoader(ntpLoader);
119+
ntpOutput.innerHTML = "";
120+
121+
fetch("/api/v1/ntp/set", {
122+
method: "POST",
123+
headers: { "Content-Type": "application/json" },
124+
body: JSON.stringify({ ntp_domain: ntpDomain }),
125+
})
126+
.then((res) => res.json())
127+
.then((data) => {
128+
if (!data || data.success === false) {
129+
throw new Error(data.message || "Unknown error");
130+
}
131+
ntpOutput.innerHTML = `<p style="color: #4CAF50;">✅ NTP server updated successfully to <strong>${ntpDomain}</strong></p>`;
132+
})
133+
.catch((err) => {
134+
ntpOutput.innerHTML = `<p style="color: var(--error-color);">⚠️ ${err.message}</p>`;
135+
})
136+
.finally(() => {
137+
hideLoader(ntpLoader);
138+
enableButton(ntpSetBtn, "Set NTP Server");
139+
});
140+
};
141+
98142
document.addEventListener("click", (e) => {
99143
if (e.target.classList.contains("connect-btn")) {
100144
const ssid = decodeURIComponent(e.target.dataset.ssid);
@@ -147,4 +191,7 @@ document.addEventListener("DOMContentLoaded", () => {
147191
wifiBtn,
148192
wifiLoader
149193
);
194+
195+
ntpSetBtn.dataset.originalText = ntpSetBtn.innerText;
196+
ntpSetBtn.onclick = handleNtpUpdate;
150197
});

0 commit comments

Comments
 (0)