Files
pyMC_Repeater/repeater/templates/configuration.html

226 lines
11 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>pyMC Repeater - Configuration</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div class="layout">
<!-- Navigation Component -->
<!-- NAVIGATION_PLACEHOLDER -->
<!-- Main Content -->
<main class="content">
<header>
<h1>Configuration</h1>
<p>System configuration and settings</p>
</header>
<div class="info-box">
Configuration is read-only. To modify settings, edit the config file and restart the daemon.
</div>
<!-- CAD Calibration Tool -->
<div class="info-box" style="background: var(--accent-color); color: white; border: none;">
<strong>CAD Calibration Tool Available</strong>
<p style="margin: 8px 0 0 0;">
Optimize your Channel Activity Detection settings for better mesh performance.
<a href="/cad-calibration" style="color: white; text-decoration: underline;">Launch CAD Calibration Tool →</a>
</p>
</div>
<!-- Radio Configuration -->
<h2>Radio Settings</h2>
<div class="config-section">
<div class="config-item">
<div class="config-label">Frequency</div>
<div class="config-value" id="radio-freq">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Spreading Factor</div>
<div class="config-value" id="radio-sf">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Bandwidth</div>
<div class="config-value" id="radio-bw">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">TX Power</div>
<div class="config-value" id="radio-tx">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Coding Rate</div>
<div class="config-value" id="radio-cr">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Preamble Length</div>
<div class="config-value" id="radio-preamble">Loading...</div>
</div>
</div>
<!-- Repeater Configuration -->
<h2>Repeater Settings</h2>
<div class="config-section">
<div class="config-item">
<div class="config-label">Node Name</div>
<div class="config-value" id="node-name">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Local Hash</div>
<div class="config-value" id="local-hash">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Public Key</div>
<div class="config-value" id="public-key" style="word-break: break-all; font-family: monospace; font-size: 0.9em;">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Latitude</div>
<div class="config-value" id="latitude">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Longitude</div>
<div class="config-value" id="longitude">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Mode</div>
<div class="config-value" id="repeater-mode">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Periodic Advertisement Interval</div>
<div class="config-value" id="send-advert-interval">Loading...</div>
<div class="config-help">How often the repeater sends an advertisement packet (0 = disabled)</div>
</div>
</div>
<!-- Duty Cycle -->
<h2>Duty Cycle</h2>
<div class="config-section">
<div class="config-item">
<div class="config-label">Max Airtime %</div>
<div class="config-value" id="duty-cycle">Loading...</div>
</div>
<div class="config-item">
<div class="config-label">Enforcement</div>
<div class="config-value" id="duty-enforcement">Loading...</div>
</div>
</div>
<!-- TX Delays -->
<h2>Transmission Delays</h2>
<div class="config-section">
<div class="config-item">
<div class="config-label">Flood TX Delay Factor</div>
<div class="config-value" id="tx-delay-factor">Loading...</div>
<div class="config-help">Multiplier for flood packet transmission delays (collision avoidance)</div>
</div>
<div class="config-item">
<div class="config-label">Direct TX Delay Factor</div>
<div class="config-value" id="direct-tx-delay-factor">Loading...</div>
<div class="config-help">Base delay for direct-routed packet transmission (seconds)</div>
</div>
</div>
</main>
</div>
<script>
let currentConfig = {};
function loadConfiguration() {
fetch('/api/stats')
.then(r => r.json())
.then(data => {
currentConfig = data;
const config = data.config || {};
const radio = config.radio || {};
const dutyCycle = config.duty_cycle || {};
const delays = config.delays || {};
// Update radio settings
if (radio.frequency) {
document.getElementById('radio-freq').textContent = (radio.frequency / 1000000).toFixed(3) + ' MHz';
}
if (radio.spreading_factor) {
document.getElementById('radio-sf').textContent = radio.spreading_factor;
}
if (radio.bandwidth) {
document.getElementById('radio-bw').textContent = (radio.bandwidth / 1000).toFixed(1) + ' kHz';
}
if (radio.tx_power !== undefined) {
document.getElementById('radio-tx').textContent = radio.tx_power + ' dBm';
}
if (radio.coding_rate) {
document.getElementById('radio-cr').textContent = '4/' + radio.coding_rate;
}
if (radio.preamble_length) {
document.getElementById('radio-preamble').textContent = radio.preamble_length + ' symbols';
}
// Update repeater settings
if (config.node_name) {
document.getElementById('node-name').textContent = config.node_name;
}
if (data.local_hash) {
document.getElementById('local-hash').textContent = data.local_hash;
}
if (data.public_key) {
document.getElementById('public-key').textContent = data.public_key;
} else {
document.getElementById('public-key').textContent = 'Not set';
}
if (config.repeater && config.repeater.latitude !== undefined) {
const lat = config.repeater.latitude;
document.getElementById('latitude').textContent = lat && lat !== 0 ? lat.toFixed(6) : 'Not set';
}
if (config.repeater && config.repeater.longitude !== undefined) {
const lng = config.repeater.longitude;
document.getElementById('longitude').textContent = lng && lng !== 0 ? lng.toFixed(6) : 'Not set';
}
if (config.repeater && config.repeater.mode) {
const mode = config.repeater.mode;
document.getElementById('repeater-mode').textContent =
mode.charAt(0).toUpperCase() + mode.slice(1);
}
if (config.repeater && config.repeater.send_advert_interval_hours !== undefined) {
const interval = config.repeater.send_advert_interval_hours;
if (interval === 0) {
document.getElementById('send-advert-interval').textContent = 'Disabled';
} else {
document.getElementById('send-advert-interval').textContent = interval + ' hour' + (interval !== 1 ? 's' : '');
}
}
// Update duty cycle
if (dutyCycle.max_airtime_percent !== undefined) {
document.getElementById('duty-cycle').textContent = dutyCycle.max_airtime_percent.toFixed(1) + '%';
}
document.getElementById('duty-enforcement').textContent =
dutyCycle.enforcement_enabled ? 'Enabled' : 'Disabled';
// Update delays
if (delays.tx_delay_factor !== undefined) {
document.getElementById('tx-delay-factor').textContent = delays.tx_delay_factor.toFixed(2) + 'x';
}
if (delays.direct_tx_delay_factor !== undefined) {
document.getElementById('direct-tx-delay-factor').textContent = delays.direct_tx_delay_factor.toFixed(2) + 's';
}
})
.catch(e => {
console.error('Error loading configuration:', e);
// Show error in UI
document.querySelectorAll('.config-value').forEach(el => {
if (el.textContent === 'Loading...') {
el.textContent = 'Error';
el.style.color = '#f48771';
}
});
});
}
// Load configuration on page load
document.addEventListener('DOMContentLoaded', loadConfiguration);
</script>
</body>
</html>