310 lines
9.4 KiB
HTML
310 lines
9.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>LED Controller - Settings</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
<style>
|
|
.settings-container {
|
|
padding: 2rem;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
overflow-y: auto;
|
|
height: 100%;
|
|
}
|
|
|
|
.settings-header {
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.settings-header h1 {
|
|
font-size: 2rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.settings-header p {
|
|
color: #aaa;
|
|
}
|
|
|
|
.settings-section {
|
|
background-color: #1a1a1a;
|
|
border-radius: 8px;
|
|
padding: 1.5rem;
|
|
margin-bottom: 1.5rem;
|
|
border: 1px solid #4a4a4a;
|
|
}
|
|
|
|
.settings-section h2 {
|
|
font-size: 1.3rem;
|
|
margin-bottom: 1rem;
|
|
color: #fff;
|
|
border-bottom: 2px solid #4a4a4a;
|
|
padding-bottom: 0.5rem;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.form-group label {
|
|
display: block;
|
|
margin-bottom: 0.5rem;
|
|
color: #ccc;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.form-group input[type="text"],
|
|
.form-group input[type="password"],
|
|
.form-group input[type="number"],
|
|
.form-group select {
|
|
width: 100%;
|
|
padding: 0.75rem;
|
|
background-color: #2e2e2e;
|
|
border: 1px solid #4a4a4a;
|
|
border-radius: 4px;
|
|
color: white;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.form-group input:focus,
|
|
.form-group select:focus {
|
|
outline: none;
|
|
border-color: #5a5a5a;
|
|
}
|
|
|
|
.form-group small {
|
|
display: block;
|
|
margin-top: 0.25rem;
|
|
color: #888;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.form-row {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.status-info {
|
|
background-color: #2e2e2e;
|
|
border: 1px solid #4a4a4a;
|
|
border-radius: 4px;
|
|
padding: 1rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.status-info h3 {
|
|
font-size: 1rem;
|
|
margin-bottom: 0.5rem;
|
|
color: #fff;
|
|
}
|
|
|
|
.status-info p {
|
|
color: #aaa;
|
|
margin: 0.25rem 0;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.status-connected {
|
|
color: #4caf50;
|
|
}
|
|
|
|
.status-disconnected {
|
|
color: #f44336;
|
|
}
|
|
|
|
.btn-group {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.btn-full {
|
|
flex: 1;
|
|
}
|
|
|
|
.back-link {
|
|
display: inline-block;
|
|
margin-bottom: 1rem;
|
|
color: #aaa;
|
|
text-decoration: none;
|
|
padding: 0.5rem 1rem;
|
|
border-radius: 4px;
|
|
transition: background-color 0.2s;
|
|
}
|
|
|
|
.back-link:hover {
|
|
background-color: #2e2e2e;
|
|
color: white;
|
|
}
|
|
|
|
.message {
|
|
padding: 0.75rem;
|
|
border-radius: 4px;
|
|
margin-bottom: 1rem;
|
|
display: none;
|
|
}
|
|
|
|
.message.success {
|
|
background-color: #1b5e20;
|
|
color: #4caf50;
|
|
border: 1px solid #4caf50;
|
|
}
|
|
|
|
.message.error {
|
|
background-color: #5e1b1b;
|
|
color: #f44336;
|
|
border: 1px solid #f44336;
|
|
}
|
|
|
|
.message.show {
|
|
display: block;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="app-container">
|
|
<div class="settings-container">
|
|
<a href="/" class="back-link">← Back to Dashboard</a>
|
|
|
|
<div class="settings-header">
|
|
<h1>Device Settings</h1>
|
|
<p>Configure WiFi Access Point settings</p>
|
|
</div>
|
|
|
|
<div id="message" class="message"></div>
|
|
|
|
<!-- WiFi Access Point Settings -->
|
|
<div class="settings-section">
|
|
<h2>WiFi Access Point Settings</h2>
|
|
|
|
<div id="ap-status" class="status-info">
|
|
<h3>AP Status</h3>
|
|
<p>Loading...</p>
|
|
</div>
|
|
|
|
<form id="ap-form">
|
|
<div class="form-group">
|
|
<label for="ap-ssid">AP SSID (Network Name)</label>
|
|
<input type="text" id="ap-ssid" name="ssid" placeholder="Enter AP name" required>
|
|
<small>The name of the WiFi access point this device creates</small>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="ap-password">AP Password</label>
|
|
<input type="password" id="ap-password" name="password" placeholder="Enter AP password (min 8 chars)" data-bwignore>
|
|
<small>Leave empty for open network (min 8 characters if set)</small>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="ap-channel">Channel (1-11)</label>
|
|
<input type="number" id="ap-channel" name="channel" min="1" max="11" placeholder="Auto">
|
|
<small>WiFi channel (1-11 for 2.4GHz). Leave empty for auto.</small>
|
|
</div>
|
|
|
|
<div class="btn-group">
|
|
<button type="submit" class="btn btn-primary btn-full">Configure AP</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Show message helper
|
|
function showMessage(text, type = 'success') {
|
|
const messageEl = document.getElementById('message');
|
|
messageEl.textContent = text;
|
|
messageEl.className = `message ${type} show`;
|
|
setTimeout(() => {
|
|
messageEl.classList.remove('show');
|
|
}, 5000);
|
|
}
|
|
|
|
// Load AP status and config
|
|
async function loadAPStatus() {
|
|
try {
|
|
const response = await fetch('/settings/wifi/ap');
|
|
const config = await response.json();
|
|
|
|
const statusEl = document.getElementById('ap-status');
|
|
if (config.active) {
|
|
statusEl.innerHTML = `
|
|
<h3>AP Status: <span class="status-connected">Active</span></h3>
|
|
<p><strong>SSID:</strong> ${config.ssid || 'N/A'}</p>
|
|
<p><strong>Channel:</strong> ${config.channel || 'Auto'}</p>
|
|
<p><strong>IP Address:</strong> ${config.ip || 'N/A'}</p>
|
|
`;
|
|
} else {
|
|
statusEl.innerHTML = `
|
|
<h3>AP Status: <span class="status-disconnected">Inactive</span></h3>
|
|
<p>Access Point is not currently active</p>
|
|
`;
|
|
}
|
|
|
|
// Load saved values
|
|
if (config.saved_ssid) document.getElementById('ap-ssid').value = config.saved_ssid;
|
|
if (config.saved_channel) document.getElementById('ap-channel').value = config.saved_channel;
|
|
} catch (error) {
|
|
console.error('Error loading AP status:', error);
|
|
}
|
|
}
|
|
|
|
// AP form submission
|
|
document.getElementById('ap-form').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const formData = {
|
|
ssid: document.getElementById('ap-ssid').value,
|
|
password: document.getElementById('ap-password').value,
|
|
channel: document.getElementById('ap-channel').value || null
|
|
};
|
|
|
|
// Validate password length if provided
|
|
if (formData.password && formData.password.length > 0 && formData.password.length < 8) {
|
|
showMessage('AP password must be at least 8 characters', 'error');
|
|
return;
|
|
}
|
|
|
|
// Convert channel to number if provided
|
|
if (formData.channel) {
|
|
formData.channel = parseInt(formData.channel);
|
|
if (formData.channel < 1 || formData.channel > 11) {
|
|
showMessage('Channel must be between 1 and 11', 'error');
|
|
return;
|
|
}
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/settings/wifi/ap', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(formData)
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (response.ok) {
|
|
showMessage('Access Point configured successfully!', 'success');
|
|
setTimeout(loadAPStatus, 1000);
|
|
} else {
|
|
showMessage(`Error: ${result.error || 'Failed to configure AP'}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
showMessage(`Error: ${error.message}`, 'error');
|
|
}
|
|
});
|
|
|
|
// Load all data on page load
|
|
loadAPStatus();
|
|
|
|
// Refresh status every 10 seconds
|
|
setInterval(loadAPStatus, 10000);
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|