This commit is contained in:
Mateusz Gruszczyński
2026-09-14 16:32:28 +02:00
parent c3fbc5ccc6
commit 021cbddba5
68 changed files with 7780 additions and 202 deletions
+89 -2
View File
@@ -1,6 +1,7 @@
const SETTINGS_ENDPOINTS = {
application: '/api/settings/application',
gree: '/api/settings/gree',
greeCloud: '/api/settings/gree-cloud',
history: '/api/settings/history',
influxdb: '/api/settings/influxdb',
notifications: '/api/settings/notifications',
@@ -13,6 +14,7 @@ function applySettingsSection(section, data) {
app.settings = app.settings || {};
if (section === 'application') app.settings.simulator_enabled = !!data.simulator_enabled;
else if (section === 'gree') Object.assign(app.settings, data);
else if (section === 'greeCloud') app.settings.gree_cloud = data;
else if (section === 'history') {
app.settings.history_retention_days = Number(data.retention_days);
app.settings.history_compaction_enabled = data.compaction_enabled !== false;
@@ -44,6 +46,18 @@ function greeSettingsBodyFromForm(form) {
};
}
function greeCloudSettingsBodyFromForm(form) {
const raw = Object.fromEntries(new FormData(form));
const body = {
enabled: form.gree_cloud_enabled.checked,
region: raw.gree_cloud_region || 'Europe',
username: raw.gree_cloud_username || '',
polling_interval_seconds: Number(raw.gree_cloud_polling_interval_seconds || 60),
};
if (raw.gree_cloud_password) body.password = raw.gree_cloud_password;
return body;
}
function historySettingsBodyFromForm(form, eventRetentionDays = null) {
const raw = Object.fromEntries(new FormData(form));
return {
@@ -99,7 +113,12 @@ function notificationSettingsBodyFromForm(form) {
}
function debugSettingsBodyFromForm(form) {
return { overlay_enabled: form.debug_overlay_enabled.checked, gree_frames: form.debug_gree_frames.checked };
return {
overlay_enabled: form.debug_overlay_enabled.checked,
gree_frames: form.debug_gree_frames.checked,
cloud_requests: form.debug_cloud_requests.checked,
cloud_mqtt: form.debug_cloud_mqtt.checked,
};
}
function nightSettingsBodyFromForm(form) {
@@ -144,9 +163,10 @@ function refreshSettingsUi() {
}
async function saveMainSettings(form, notify = true) {
const [application, gree, history, influxdb, notifications, debug] = await Promise.all([
const [application, gree, greeCloud, history, influxdb, notifications, debug] = await Promise.all([
api(SETTINGS_ENDPOINTS.application, { method: 'PUT', body: applicationSettingsBodyFromForm(form) }),
api(SETTINGS_ENDPOINTS.gree, { method: 'PUT', body: greeSettingsBodyFromForm(form) }),
api(SETTINGS_ENDPOINTS.greeCloud, { method: 'PUT', body: greeCloudSettingsBodyFromForm(form) }),
api(SETTINGS_ENDPOINTS.history, { method: 'PUT', body: historySettingsBodyFromForm(form) }),
api(SETTINGS_ENDPOINTS.influxdb, { method: 'PUT', body: influxDbSettingsBodyFromForm(form) }),
api(SETTINGS_ENDPOINTS.notifications, { method: 'PUT', body: notificationSettingsBodyFromForm(form) }),
@@ -154,6 +174,7 @@ async function saveMainSettings(form, notify = true) {
]);
applySettingsSection('application', application);
applySettingsSection('gree', gree);
applySettingsSection('greeCloud', greeCloud);
applySettingsSection('history', history);
applySettingsSection('influxdb', influxdb);
applySettingsSection('notifications', notifications);
@@ -300,6 +321,8 @@ document.addEventListener('change', event => {
const target = event.target;
if (target.id === 'historyZoneSelect') { app.historyZone = target.value; updateBrowserUrl(currentHistoryPath()); renderHistoryPage(); }
else if (target.id === 'historyDeviceSelect') { app.historyDevice = target.value; updateBrowserUrl(currentHistoryPath()); renderHistoryPage(); }
else if (target.id === 'historyEnergyDeviceSelect') { app.historyEnergyDevice = target.value; updateBrowserUrl(currentHistoryPath()); loadHistory(); }
else if (target.id === 'historyEnergyInterval') { app.historyEnergyInterval = target.value; updateBrowserUrl(currentHistoryPath()); loadHistory(); }
else if (target.id === 'historySensorSelect') { app.historySensor = target.value; updateBrowserUrl(currentHistoryPath()); renderHistoryPage(); }
else if (target.name === 'influx_version') updateInfluxFields();
});
@@ -385,3 +408,67 @@ document.addEventListener('click', event => {
renderFlowSharedInputs();
updateDirtyIndicator($('#homeAssistantForm'));
});
async function saveGreeCloudSettings(form = $('#settingsForm')) {
const data = await api(SETTINGS_ENDPOINTS.greeCloud, { method: 'PUT', body: greeCloudSettingsBodyFromForm(form) });
applySettingsSection('greeCloud', data);
return data;
}
function renderCloudDiscoveryDevices(devices) {
const list = $('#cloudDiscoveryList');
if (!list) return;
const items = Array.isArray(devices) ? devices : [];
list.innerHTML = items.length ? items.map(device => `
<div class="discovery-name-row cloud-discovery-row">
<span><strong>${esc(device.name || 'GREE')}</strong><small>${esc(device.model || 'GREE')} · ${esc(device.mac || device.id)} · ${esc(tr(device.online ? 'status.online' : 'status.offline'))}</small></span>
<button type="button" class="${device.already_added ? 'secondary' : 'primary'}" data-action="add-cloud-device" data-cloud-id="${esc(device.id)}" ${device.already_added ? 'disabled' : ''}>${esc(device.already_added ? tr('devices.cloudAlreadyAdded') : tr('actions.add'))}</button>
</div>`).join('') : `<div class="empty"><strong>${esc(tr('devices.cloudDiscoveryEmpty'))}</strong>${esc(tr('devices.cloudDiscoveryEmptyHint'))}</div>`;
}
async function loadCloudDiscovery({ open = true } = {}) {
const result = await api('/api/integrations/gree-cloud/devices');
renderCloudDiscoveryDevices(result.devices || []);
if (open) openDialog('cloudDiscoveryDialog');
return result;
}
$('#greeCloudTestButton')?.addEventListener('click', async event => {
const button = event.currentTarget;
const form = $('#settingsForm');
const resultBox = $('#greeCloudTestResult');
button.disabled = true;
if (resultBox) { resultBox.hidden = true; resultBox.classList.remove('success', 'error'); }
try {
await saveGreeCloudSettings(form);
const result = await api('/api/integrations/gree-cloud/test', { method: 'POST' });
if (resultBox) {
resultBox.hidden = false;
resultBox.classList.add(result.ok ? 'success' : 'error');
resultBox.textContent = result.ok ? `Connected. ${Number(result.device_count || 0)} device(s) found.` : (result.message || result.status || 'Connection failed');
}
if (result.ok) {
const refreshed = await api(SETTINGS_ENDPOINTS.greeCloud);
applySettingsSection('greeCloud', refreshed);
renderSettings();
}
} catch (error) {
if (resultBox) { resultBox.hidden = false; resultBox.classList.add('error'); resultBox.textContent = error.message; }
} finally { button.disabled = false; }
});
$('#greeCloudRefreshButton')?.addEventListener('click', async event => {
const button = event.currentTarget;
button.disabled = true;
try { await saveGreeCloudSettings($('#settingsForm')); await loadCloudDiscovery(); }
catch (error) { toast(error.message, true); }
finally { button.disabled = false; }
});
$('#cloudDiscoveryRefresh')?.addEventListener('click', async event => {
const button = event.currentTarget;
button.disabled = true;
try { await loadCloudDiscovery({ open: false }); }
catch (error) { toast(error.message, true); }
finally { button.disabled = false; }
});