v0.14.2-connectivity
This commit is contained in:
Vendored
+3
@@ -15,6 +15,9 @@ function settingsFromSnapshot(sections, houseMode = app.settings?.house_mode ||
|
||||
zone_interval_seconds: Number(gree.zone_interval_seconds),
|
||||
discovery_timeout_ms: Number(gree.discovery_timeout_ms),
|
||||
discovery_broadcast: gree.discovery_broadcast,
|
||||
ping_metrics_enabled: gree.ping_metrics_enabled !== false,
|
||||
ping_interval_seconds: Number(gree.ping_interval_seconds || 60),
|
||||
ping_sample_count: Number(gree.ping_sample_count || 3),
|
||||
suppress_device_beep: !!gree.suppress_device_beep,
|
||||
gree_cloud: greeCloud,
|
||||
compressor_protection_enabled: gree.compressor_protection_enabled !== false,
|
||||
|
||||
+23
-8
@@ -106,6 +106,11 @@ function renderHistoryNavigation() {
|
||||
const intervalSelect = $('#historyEnergyInterval'); if (intervalSelect) intervalSelect.value = app.historyEnergyInterval;
|
||||
const compareSelect = $('#historyEnergyCompare'); if (compareSelect) compareSelect.value = app.historyEnergyCompare;
|
||||
if (energyPickerWasOpen && $('#historyEnergyTargetPicker')) $('#historyEnergyTargetPicker').open = true;
|
||||
} else if (app.historyTab === 'network') {
|
||||
const targets = app.historyNetworkTargets || [];
|
||||
const targetOptions = targets.map(target => `<option value="${esc(target.id)}">${esc(target.name)}</option>`).join('');
|
||||
host.innerHTML = `<label><span>${esc(tr('history.networkTarget'))}</span><select id="historyNetworkSelect"><option value="all">${esc(tr('history.allNetworkTargets'))}</option>${targetOptions}</select></label>`;
|
||||
const select = $('#historyNetworkSelect'); if ([...select.options].some(option => option.value === app.historyNetworkTarget)) select.value = app.historyNetworkTarget;
|
||||
} else if (app.historyTab === 'sensors') {
|
||||
host.innerHTML = `<label><span>${esc(tr('history.haSensor'))}</span><select id="historySensorSelect"><option value="all">${esc(tr('history.allSensors'))}</option>${options.sensors}</select></label>`;
|
||||
const select = $('#historySensorSelect'); if ([...select.options].some(option => option.value === app.historySensor)) select.value = app.historySensor;
|
||||
@@ -129,6 +134,16 @@ async function loadHistory() {
|
||||
if (app.currentView === 'history') updateBrowserUrl(currentHistoryPath(), true);
|
||||
return;
|
||||
}
|
||||
if (app.historyTab === 'network') {
|
||||
const target = app.historyNetworkTarget && app.historyNetworkTarget !== 'all' ? `&target_id=${encodeURIComponent(app.historyNetworkTarget)}` : '';
|
||||
const data = await api(`/api/history/network?hours=${encodeURIComponent(hours)}&limit=20000${target}`);
|
||||
app.historyNetwork = data.readings || [];
|
||||
app.historyNetworkTargets = data.targets || [];
|
||||
renderHistoryNavigation();
|
||||
renderHistoryPage();
|
||||
if (app.currentView === 'history') updateBrowserUrl(currentHistoryPath(), true);
|
||||
return;
|
||||
}
|
||||
const data = await api(`/api/history?scope=overview&hours=${encodeURIComponent(hours)}&limit=20000`);
|
||||
app.historyData = { zones: data.zones || [], devices: data.devices || [], sensors: data.sensors || [] };
|
||||
app.historyCounts = data.counts || {};
|
||||
@@ -323,11 +338,11 @@ function nearestPoint(points, targetTs) {
|
||||
return Math.abs(before.ts - targetTs) <= Math.abs(after.ts - targetTs) ? before : after;
|
||||
}
|
||||
|
||||
function formatChartTooltipValue(item, point, binaryLabels) {
|
||||
function formatChartTooltipValue(item, point, binaryLabels, tooltipUnit = ' °C') {
|
||||
if (!point || !Number.isFinite(point.value)) return '—';
|
||||
if (typeof item.tooltipValue === 'function') return String(item.tooltipValue(point.value, point.row));
|
||||
const formatted = Number(point.value).toLocaleString(locale(), { minimumFractionDigits: 1, maximumFractionDigits: 2 });
|
||||
return binaryLabels ? formatted : `${formatted} °C`;
|
||||
return binaryLabels ? formatted : `${formatted}${tooltipUnit}`;
|
||||
}
|
||||
|
||||
function bindChartTooltip(canvas, series, sortedRows, geometry) {
|
||||
@@ -337,7 +352,7 @@ function bindChartTooltip(canvas, series, sortedRows, geometry) {
|
||||
const selection = wrap?.querySelector('.chart-selection');
|
||||
if (!canvas || !wrap || !tooltip || !line) return;
|
||||
|
||||
const { pad, width, height, firstTs, lastTs, binaryLabels } = geometry;
|
||||
const { pad, width, height, firstTs, lastTs, binaryLabels, tooltipUnit } = geometry;
|
||||
const plotWidth = width - pad.left - pad.right;
|
||||
const timestamps = [...new Set(sortedRows.map(row => new Date(row.timestamp).getTime()).filter(Number.isFinite))].sort((a, b) => a - b);
|
||||
const timestampPoints = timestamps.map(ts => ({ ts, value: ts }));
|
||||
@@ -367,7 +382,7 @@ function bindChartTooltip(canvas, series, sortedRows, geometry) {
|
||||
$$('.chart-hover-line').forEach(node => { if (node !== line) node.hidden = true; });
|
||||
tooltip.innerHTML = `<strong class="chart-tooltip-time">${esc(chartPreciseTime(snapped))}</strong><div class="chart-tooltip-values">${values.map(({ item, point }) => {
|
||||
const sampleTime = Math.abs(point.ts - snapped) > 1000 ? `<small class="chart-tooltip-sample-time">${esc(chartPreciseTime(point.ts))}</small>` : '';
|
||||
return `<div class="chart-tooltip-row"><span class="chart-tooltip-label"><i style="--tooltip-color:${esc(item.color)}"></i><span>${esc(item.label)}</span></span><span class="chart-tooltip-value">${esc(formatChartTooltipValue(item, point, binaryLabels))}${sampleTime}</span></div>`;
|
||||
return `<div class="chart-tooltip-row"><span class="chart-tooltip-label"><i style="--tooltip-color:${esc(item.color)}"></i><span>${esc(item.label)}</span></span><span class="chart-tooltip-value">${esc(formatChartTooltipValue(item, point, binaryLabels, tooltipUnit))}${sampleTime}</span></div>`;
|
||||
}).join('')}</div>`;
|
||||
tooltip.hidden = false;
|
||||
line.hidden = false;
|
||||
@@ -454,9 +469,9 @@ function bindChartTooltip(canvas, series, sortedRows, geometry) {
|
||||
};
|
||||
}
|
||||
|
||||
function drawLineChart(canvas, series, rows, { height = 340, minValue = null, maxValue = null, binaryLabels = false } = {}) {
|
||||
function drawLineChart(canvas, series, rows, { height = 340, minValue = null, maxValue = null, binaryLabels = false, axisSuffix = '°', tooltipUnit = ' °C', axisDigits = 1 } = {}) {
|
||||
if (!canvas) return;
|
||||
const options = { height, minValue, maxValue, binaryLabels };
|
||||
const options = { height, minValue, maxValue, binaryLabels, axisSuffix, tooltipUnit, axisDigits };
|
||||
if (canvas.id) chartRuntime.set(canvas.id, { series, rows, options });
|
||||
const visibleSeries = series.filter((item, index) => !isChartSeriesHidden(canvas.id, item, index));
|
||||
if (!rows.length || !visibleSeries.length) return drawEmptyChart(canvas, height);
|
||||
@@ -482,7 +497,7 @@ function drawLineChart(canvas, series, rows, { height = 340, minValue = null, ma
|
||||
for (let i = 0; i <= 5; i++) {
|
||||
const value = min + (max - min) * i / 5, py = y(value);
|
||||
ctx.beginPath(); ctx.moveTo(pad.left, py); ctx.lineTo(width - pad.right, py); ctx.stroke();
|
||||
ctx.textAlign = 'right'; ctx.fillText(binaryLabels ? value.toFixed(0) : `${value.toFixed(1)}°`, pad.left - 8, py + 3);
|
||||
ctx.textAlign = 'right'; ctx.fillText(binaryLabels ? value.toFixed(0) : `${value.toFixed(axisDigits)}${axisSuffix}`, pad.left - 8, py + 3);
|
||||
}
|
||||
const ticks = width < 420 ? 2 : width < 620 ? 3 : 5;
|
||||
for (let i = 0; i <= ticks; i++) {
|
||||
@@ -501,7 +516,7 @@ function drawLineChart(canvas, series, rows, { height = 340, minValue = null, ma
|
||||
});
|
||||
ctx.stroke(); ctx.setLineDash([]);
|
||||
});
|
||||
bindChartTooltip(canvas, visibleSeries, sortedRows, { pad, width, height, firstTs, lastTs, binaryLabels });
|
||||
bindChartTooltip(canvas, visibleSeries, sortedRows, { pad, width, height, firstTs, lastTs, binaryLabels, tooltipUnit });
|
||||
}
|
||||
|
||||
function energyBucketLabel(timestamp, interval) {
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ const app = {
|
||||
currentView: 'dashboard', loading: false, bootstrapReloadPending: false, language: preferredLanguage, theme: preferredTheme, connectionStatus: 'connecting',
|
||||
languages: [], translations: {}, locales: {},
|
||||
historyTab: 'overview', historyData: { zones: [], devices: [], sensors: [] }, historyCounts: {},
|
||||
historyZone: 'all', historyDevice: 'all', historySensor: 'all', historyEnergyDevice: '', historyEnergyTargets: [], historyEnergyInterval: 'daily', historyEnergyCompare: 'none', historyEnergy: [], historyLoading: false, historyReloadPending: false,
|
||||
historyZone: 'all', historyDevice: 'all', historySensor: 'all', historyNetworkTarget: 'all', historyNetwork: [], historyNetworkTargets: [], historyEnergyDevice: '', historyEnergyTargets: [], historyEnergyInterval: 'daily', historyEnergyCompare: 'none', historyEnergy: [], historyLoading: false, historyReloadPending: false,
|
||||
customChartSeries: [], savedCharts: [], chartZooms: {}, chartHiddenSeries: {}, zoneControlSeq: {}, groupControlSeq: {}, zoneControlQueue: {}, groupControlQueue: {}, deviceControlQueue: {}, houseControlQueue: null, climateControlQueue: null, groupCustomDrafts: {}, zoneTemperatureTimers: {}, deviceTemperatureDrafts: {},
|
||||
controlPlan: null, controlPlanRevision: null, controlPlanPushReady: false, controlPlanTimer: null, debugLines: [], debugBacklogLoaded: false, debugFilter: 'all', sensorAliases: {}, flowSharedInputs: [], flowSharedInputValueCache: {}, flowSharedInputValueRequests: {}, flowSharedInputValueTimer: null,
|
||||
simulationScope: 'units', simulationTarget: 'all', standaloneSimulation: false, dashboardTab: 'main', settingsTab: 'app', systemSnapshotAt: Date.now(),
|
||||
|
||||
@@ -29,6 +29,7 @@ function outdoorHistorySeries(devices, rows) {
|
||||
function renderHistorySummary() {
|
||||
const host = $('#historySummary'); if (!host) return;
|
||||
if (app.historyTab === 'energy') { renderEnergyHistorySummary(); return; }
|
||||
if (app.historyTab === 'network') { renderNetworkHistorySummary(); return; }
|
||||
const deviceRows = app.historyData.devices, zoneRows = app.historyData.zones, sensorRows = app.historyData.sensors;
|
||||
const cards = [
|
||||
[tr('history.deviceSamples'), app.historyCounts.devices ?? deviceRows.length, tr('history.greeHistory')],
|
||||
@@ -113,6 +114,67 @@ function renderSensorHistory() {
|
||||
drawLineChart($('#haSensorsChart'), series, rows, { height: 370 }); renderLegend($('#haSensorsChartLegend'), series);
|
||||
}
|
||||
|
||||
function networkTargetRows() {
|
||||
const selected = app.historyNetworkTarget || 'all';
|
||||
return selected === 'all' ? (app.historyNetwork || []) : (app.historyNetwork || []).filter(row => row.target_id === selected);
|
||||
}
|
||||
|
||||
function networkTargetLabel(id) {
|
||||
return (app.historyNetworkTargets || []).find(target => target.id === id)?.name || id;
|
||||
}
|
||||
|
||||
function renderNetworkHistorySummary() {
|
||||
const host = $('#historySummary'); if (!host) return;
|
||||
const rows = networkTargetRows();
|
||||
const ids = [...new Set(rows.map(row => row.target_id))];
|
||||
if (!ids.length) { host.innerHTML = ''; return; }
|
||||
host.innerHTML = ids.map(id => {
|
||||
const latest = rows.filter(row => row.target_id === id).sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))[0];
|
||||
const latency = Number.isFinite(Number(latest?.latency_ms)) ? `${Number(latest.latency_ms).toLocaleString(locale(), { maximumFractionDigits: 1 })} ms` : '—';
|
||||
const jitter = Number.isFinite(Number(latest?.jitter_ms)) ? `${Number(latest.jitter_ms).toLocaleString(locale(), { maximumFractionDigits: 1 })} ms` : '—';
|
||||
const loss = `${Number(latest?.packet_loss_pct || 0).toLocaleString(locale(), { maximumFractionDigits: 1 })}%`;
|
||||
return `<div class="history-stat"><small>${esc(networkTargetLabel(id))}</small><strong>${esc(latency)}</strong><span>${esc(tr('history.networkJitter'))}: ${esc(jitter)} · ${esc(tr('history.networkLoss'))}: ${esc(loss)} · ${esc(latest?.successful_samples ?? 0)}/${esc(latest?.sample_count ?? 0)}</span></div>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function renderNetworkHistory() {
|
||||
const host = $('#historyCharts'); if (!host) return;
|
||||
renderNetworkHistorySummary();
|
||||
const rows = networkTargetRows();
|
||||
if (!rows.length) {
|
||||
host.innerHTML = `<div class="empty"><strong>${esc(tr('history.networkNoData'))}</strong><span>${esc(tr('history.networkNoDataHint'))}</span></div>`;
|
||||
return;
|
||||
}
|
||||
const ids = [...new Set(rows.map(row => row.target_id))];
|
||||
const latencySeries = [];
|
||||
const lossSeries = [];
|
||||
ids.forEach((id, index) => {
|
||||
const label = networkTargetLabel(id);
|
||||
const color = historySeriesColor(index);
|
||||
latencySeries.push({
|
||||
key: `${id}:latency`, label: `${label} · ${tr('history.networkLatency')}`, color,
|
||||
value: row => row.target_id === id ? historyNumber(row.latency_ms) : NaN,
|
||||
tooltipValue: value => `${Number(value).toLocaleString(locale(), { maximumFractionDigits: 2 })} ms`,
|
||||
});
|
||||
latencySeries.push({
|
||||
key: `${id}:jitter`, label: `${label} · ${tr('history.networkJitter')}`, color, dash: [5, 4],
|
||||
value: row => row.target_id === id ? historyNumber(row.jitter_ms) : NaN,
|
||||
tooltipValue: value => `${Number(value).toLocaleString(locale(), { maximumFractionDigits: 2 })} ms`,
|
||||
});
|
||||
lossSeries.push({
|
||||
key: `${id}:loss`, label, color,
|
||||
value: row => row.target_id === id ? historyNumber(row.packet_loss_pct) : NaN,
|
||||
tooltipValue: value => `${Number(value).toLocaleString(locale(), { maximumFractionDigits: 2 })}%`,
|
||||
});
|
||||
});
|
||||
host.innerHTML = historyChartMarkup('networkLatencyChart', tr('history.networkLatencyJitter'), tr('history.networkLatencyJitterHint'))
|
||||
+ historyChartMarkup('networkLossChart', tr('history.networkLoss'), tr('history.networkLossHint'));
|
||||
drawLineChart($('#networkLatencyChart'), latencySeries, rows, { height: 360, minValue: 0, axisSuffix: ' ms', tooltipUnit: ' ms', axisDigits: 0 });
|
||||
renderLegend($('#networkLatencyChartLegend'), latencySeries);
|
||||
drawLineChart($('#networkLossChart'), lossSeries, rows, { height: 300, minValue: 0, maxValue: 100, axisSuffix: '%', tooltipUnit: '%', axisDigits: 0 });
|
||||
renderLegend($('#networkLossChartLegend'), lossSeries);
|
||||
}
|
||||
|
||||
function customSeriesOptions() {
|
||||
const items = [];
|
||||
const groupedOutdoorIds = new Set();
|
||||
@@ -203,6 +265,7 @@ function renderHistoryPage() {
|
||||
else if (app.historyTab === 'zones') renderZoneHistory();
|
||||
else if (app.historyTab === 'devices') renderDeviceHistory();
|
||||
else if (app.historyTab === 'energy') renderEnergyHistory();
|
||||
else if (app.historyTab === 'network') renderNetworkHistory();
|
||||
else if (app.historyTab === 'sensors') renderSensorHistory();
|
||||
else renderCustomHistory();
|
||||
}
|
||||
|
||||
@@ -127,14 +127,15 @@ function renderPingDialog() {
|
||||
const toggle = $('#pingToggleButton');
|
||||
const grid = $('#pingLiveGrid');
|
||||
if (!dialog || !select || !all || !toggle || !grid) return;
|
||||
if (!app.pingMonitor.targetId || !app.devices.some(device => device.id === app.pingMonitor.targetId)) app.pingMonitor.targetId = app.devices[0]?.id || '';
|
||||
select.innerHTML = app.devices.map(device => `<option value="${esc(device.id)}" ${device.id === app.pingMonitor.targetId ? 'selected' : ''}>${esc(device.name)}</option>`).join('');
|
||||
const localDevices = app.devices.filter(device => device.connection_type !== 'gree_cloud');
|
||||
if (!app.pingMonitor.targetId || !localDevices.some(device => device.id === app.pingMonitor.targetId)) app.pingMonitor.targetId = localDevices[0]?.id || '';
|
||||
select.innerHTML = localDevices.map(device => `<option value="${esc(device.id)}" ${device.id === app.pingMonitor.targetId ? 'selected' : ''}>${esc(device.name)}</option>`).join('');
|
||||
select.disabled = app.pingMonitor.all;
|
||||
all.checked = app.pingMonitor.all;
|
||||
toggle.textContent = tr(app.pingMonitor.running ? 'devices.pingStop' : 'devices.pingStart');
|
||||
toggle.classList.toggle('primary', app.pingMonitor.running);
|
||||
toggle.classList.toggle('secondary', !app.pingMonitor.running);
|
||||
const devices = app.pingMonitor.all ? app.devices : app.devices.filter(device => device.id === app.pingMonitor.targetId);
|
||||
const devices = app.pingMonitor.all ? localDevices : localDevices.filter(device => device.id === app.pingMonitor.targetId);
|
||||
grid.innerHTML = devices.length ? devices.map(device => {
|
||||
const samples = pingSamples(device.id);
|
||||
const stats = pingStats(samples);
|
||||
@@ -168,7 +169,8 @@ function schedulePingCycle(delay = null) {
|
||||
|
||||
async function runPingCycle() {
|
||||
if (!app.pingMonitor.running || !$('#pingDialog')?.open || app.pingMonitor.inFlight) return;
|
||||
const targets = app.pingMonitor.all ? [...app.devices] : app.devices.filter(device => device.id === app.pingMonitor.targetId);
|
||||
const localDevices = app.devices.filter(device => device.connection_type !== 'gree_cloud');
|
||||
const targets = app.pingMonitor.all ? [...localDevices] : localDevices.filter(device => device.id === app.pingMonitor.targetId);
|
||||
if (!targets.length) { renderPingDialog(); schedulePingCycle(); return; }
|
||||
app.pingMonitor.inFlight = true;
|
||||
await Promise.allSettled(targets.map(async (device, index) => {
|
||||
@@ -190,7 +192,7 @@ async function runPingCycle() {
|
||||
}
|
||||
|
||||
function startPingMonitor() {
|
||||
if (!app.devices.length) return;
|
||||
if (!app.devices.some(device => device.connection_type !== 'gree_cloud')) return;
|
||||
app.pingMonitor.running = true;
|
||||
renderPingDialog();
|
||||
clearTimeout(app.pingMonitor.timer);
|
||||
@@ -206,7 +208,8 @@ function stopPingMonitor() {
|
||||
}
|
||||
|
||||
function openDevicePing(id) {
|
||||
app.pingMonitor.targetId = id || app.devices[0]?.id || '';
|
||||
const localDevices = app.devices.filter(device => device.connection_type !== 'gree_cloud');
|
||||
app.pingMonitor.targetId = (id && localDevices.some(device => device.id === id)) ? id : (localDevices[0]?.id || '');
|
||||
app.pingMonitor.all = false;
|
||||
openDialog('pingDialog');
|
||||
renderPingDialog();
|
||||
|
||||
+3
-1
@@ -13,7 +13,7 @@ const VIEW_ROUTES = Object.freeze({
|
||||
logs: '/events',
|
||||
});
|
||||
const ROUTE_VIEWS = Object.freeze(Object.fromEntries(Object.entries(VIEW_ROUTES).map(([view, path]) => [path, view])));
|
||||
const HISTORY_TABS = Object.freeze(['overview', 'zones', 'devices', 'energy', 'sensors', 'custom']);
|
||||
const HISTORY_TABS = Object.freeze(['overview', 'zones', 'devices', 'energy', 'network', 'sensors', 'custom']);
|
||||
let routerInitialized = false;
|
||||
|
||||
function currentHistoryPath() {
|
||||
@@ -26,6 +26,7 @@ function currentHistoryPath() {
|
||||
if (tab === 'energy' && app.historyEnergyTargets?.length) params.set('targets', app.historyEnergyTargets.join(','));
|
||||
if (tab === 'energy' && app.historyEnergyInterval !== 'daily') params.set('interval', app.historyEnergyInterval);
|
||||
if (tab === 'energy' && app.historyEnergyCompare !== 'none') params.set('compare', app.historyEnergyCompare);
|
||||
if (tab === 'network' && app.historyNetworkTarget !== 'all') params.set('target', app.historyNetworkTarget);
|
||||
if (tab === 'sensors' && app.historySensor !== 'all') params.set('sensor', app.historySensor);
|
||||
if (tab === 'custom' && app.customChartSeries.length) params.set('chart', encodeChartSpec(app.customChartSeries));
|
||||
const query = params.toString();
|
||||
@@ -81,6 +82,7 @@ function applyRouteFromLocation() {
|
||||
if (['hourly', 'daily', 'weekly', 'monthly'].includes(params.get('interval'))) app.historyEnergyInterval = params.get('interval');
|
||||
if (['none', 'previous_day', 'previous_period', 'previous_year'].includes(params.get('compare'))) app.historyEnergyCompare = params.get('compare');
|
||||
}
|
||||
app.historyNetworkTarget = params.get('target') || 'all';
|
||||
app.historySensor = params.get('sensor') || 'all';
|
||||
const hours = params.get('hours');
|
||||
if (hours && ['6', '24', '168', '720', '2160', '8760'].includes(hours) && $('#historyHours')) $('#historyHours').value = hours;
|
||||
|
||||
@@ -173,6 +173,9 @@ function renderSettings() {
|
||||
form.zone_interval_seconds.value = app.settings.zone_interval_seconds || 5;
|
||||
form.discovery_broadcast.value = app.settings.discovery_broadcast || '255.255.255.255:7000';
|
||||
form.discovery_timeout_ms.value = app.settings.discovery_timeout_ms || 3000;
|
||||
form.ping_metrics_enabled.checked = app.settings.ping_metrics_enabled !== false;
|
||||
form.ping_interval_seconds.value = Number(app.settings.ping_interval_seconds || 60);
|
||||
form.ping_sample_count.value = Number(app.settings.ping_sample_count || 3);
|
||||
form.simulator_enabled.checked = !!app.settings.simulator_enabled;
|
||||
form.history_retention_days.value = app.settings.history_retention_days || 30;
|
||||
form.event_log_retention_days.value = app.settings.event_log_retention_days || 30;
|
||||
@@ -185,6 +188,9 @@ function renderSettings() {
|
||||
form.gree_cloud_password.value = '';
|
||||
form.gree_cloud_password.placeholder = cloud.password_configured ? tr('settings.secretSaved') : tr('settings.secretKeep');
|
||||
form.gree_cloud_polling_interval_seconds.value = Number(cloud.polling_interval_seconds || 60);
|
||||
form.gree_cloud_connectivity_metrics_enabled.checked = !!cloud.connectivity_metrics_enabled;
|
||||
form.gree_cloud_connectivity_metrics_interval_seconds.value = Number(cloud.connectivity_metrics_interval_seconds || 300);
|
||||
form.gree_cloud_connectivity_metrics_sample_count.value = Number(cloud.connectivity_metrics_sample_count || 3);
|
||||
const cloudInstance = $('#greeCloudInstanceId');
|
||||
if (cloudInstance) cloudInstance.textContent = cloud.installation_id || '—';
|
||||
const cloudLastContact = $('#greeCloudLastContact');
|
||||
|
||||
@@ -40,6 +40,9 @@ function greeSettingsBodyFromForm(form) {
|
||||
zone_interval_seconds: Number(raw.zone_interval_seconds),
|
||||
discovery_timeout_ms: Number(raw.discovery_timeout_ms),
|
||||
discovery_broadcast: raw.discovery_broadcast,
|
||||
ping_metrics_enabled: form.ping_metrics_enabled.checked,
|
||||
ping_interval_seconds: Number(raw.ping_interval_seconds || 60),
|
||||
ping_sample_count: Number(raw.ping_sample_count || 3),
|
||||
suppress_device_beep: form.suppress_device_beep.checked,
|
||||
compressor_protection_enabled: form.compressor_protection_enabled.checked,
|
||||
compressor_protection_seconds: Math.max(30, Math.min(1800, Math.round(Number(raw.compressor_protection_minutes || 3) * 60))),
|
||||
@@ -53,6 +56,9 @@ function greeCloudSettingsBodyFromForm(form) {
|
||||
region: raw.gree_cloud_region || 'Europe',
|
||||
username: raw.gree_cloud_username || '',
|
||||
polling_interval_seconds: Number(raw.gree_cloud_polling_interval_seconds || 60),
|
||||
connectivity_metrics_enabled: form.gree_cloud_connectivity_metrics_enabled.checked,
|
||||
connectivity_metrics_interval_seconds: Number(raw.gree_cloud_connectivity_metrics_interval_seconds || 300),
|
||||
connectivity_metrics_sample_count: Number(raw.gree_cloud_connectivity_metrics_sample_count || 3),
|
||||
};
|
||||
if (raw.gree_cloud_password) body.password = raw.gree_cloud_password;
|
||||
return body;
|
||||
@@ -331,6 +337,7 @@ document.addEventListener('change', event => {
|
||||
}
|
||||
else if (target.id === 'historyEnergyInterval') { app.historyEnergyInterval = target.value; updateBrowserUrl(currentHistoryPath()); loadHistory(); }
|
||||
else if (target.id === 'historyEnergyCompare') { app.historyEnergyCompare = target.value; updateBrowserUrl(currentHistoryPath()); loadHistory(); }
|
||||
else if (target.id === 'historyNetworkSelect') { app.historyNetworkTarget = target.value; updateBrowserUrl(currentHistoryPath()); loadHistory(); }
|
||||
else if (target.id === 'historySensorSelect') { app.historySensor = target.value; updateBrowserUrl(currentHistoryPath()); renderHistoryPage(); }
|
||||
else if (target.name === 'influx_version') updateInfluxFields();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user