114 lines
4.5 KiB
HTML
114 lines
4.5 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}MQTT Settings - HAMeter{% endblock %}
|
|
{% block page_title %}MQTT Settings{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="config-form-container">
|
|
<form id="mqtt-config-form" onsubmit="return false;">
|
|
<div class="form-group">
|
|
<label for="host">Host <span class="required">*</span></label>
|
|
<input type="text" id="host" name="host" value="{{ mqtt.host }}" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="port">Port</label>
|
|
<input type="number" id="port" name="port" value="{{ mqtt.port }}">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="user">Username</label>
|
|
<input type="text" id="user" name="user" value="{{ mqtt.user }}">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="password">Password</label>
|
|
<div class="input-group">
|
|
<input type="password" id="password" name="password" value="{{ '***' if mqtt.password else '' }}">
|
|
<button type="button" class="btn btn-icon" onclick="togglePassword('password')">Show</button>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="base_topic">Base Topic</label>
|
|
<input type="text" id="base_topic" name="base_topic" value="{{ mqtt.base_topic }}">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>
|
|
<input type="checkbox" id="ha_autodiscovery" name="ha_autodiscovery" {{ 'checked' if mqtt.ha_autodiscovery }}>
|
|
HA Auto-Discovery
|
|
</label>
|
|
</div>
|
|
<div class="form-group" id="ha-topic-group">
|
|
<label for="ha_autodiscovery_topic">HA Discovery Topic</label>
|
|
<input type="text" id="ha_autodiscovery_topic" name="ha_autodiscovery_topic" value="{{ mqtt.ha_autodiscovery_topic }}">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="client_id">Client ID</label>
|
|
<input type="text" id="client_id" name="client_id" value="{{ mqtt.client_id }}">
|
|
</div>
|
|
|
|
<div class="form-actions">
|
|
<button type="button" class="btn btn-secondary" onclick="testMqttConnection()">Test Connection</button>
|
|
<button type="button" class="btn btn-primary" onclick="saveMqttConfig()">Save</button>
|
|
</div>
|
|
<div class="test-result hidden" id="mqtt-test-result"></div>
|
|
</form>
|
|
</div>
|
|
|
|
<script>
|
|
async function testMqttConnection() {
|
|
const result = document.getElementById('mqtt-test-result');
|
|
result.classList.remove('hidden');
|
|
result.textContent = 'Testing...';
|
|
result.className = 'test-result';
|
|
|
|
const data = {
|
|
host: document.getElementById('host').value,
|
|
port: parseInt(document.getElementById('port').value),
|
|
user: document.getElementById('user').value,
|
|
password: document.getElementById('password').value,
|
|
};
|
|
// Don't send masked password for test
|
|
if (data.password === '***') data.password = '';
|
|
|
|
try {
|
|
const resp = await fetch('/api/config/mqtt/test', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify(data),
|
|
});
|
|
const res = await resp.json();
|
|
result.textContent = res.message;
|
|
result.className = 'test-result ' + (res.ok ? 'test-success' : 'test-error');
|
|
} catch (e) {
|
|
result.textContent = 'Error: ' + e.message;
|
|
result.className = 'test-result test-error';
|
|
}
|
|
}
|
|
|
|
async function saveMqttConfig() {
|
|
const data = {
|
|
host: document.getElementById('host').value,
|
|
port: parseInt(document.getElementById('port').value),
|
|
user: document.getElementById('user').value,
|
|
password: document.getElementById('password').value,
|
|
base_topic: document.getElementById('base_topic').value,
|
|
ha_autodiscovery: document.getElementById('ha_autodiscovery').checked,
|
|
ha_autodiscovery_topic: document.getElementById('ha_autodiscovery_topic').value,
|
|
client_id: document.getElementById('client_id').value,
|
|
};
|
|
|
|
const resp = await fetch('/api/config/mqtt', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify(data),
|
|
});
|
|
const res = await resp.json();
|
|
if (res.ok) {
|
|
showToast('MQTT settings saved', 'success');
|
|
if (res.restart_required) {
|
|
showRestartBanner();
|
|
}
|
|
} else {
|
|
showToast(res.error || 'Save failed', 'error');
|
|
}
|
|
}
|
|
</script>
|
|
{% endblock %}
|