This commit is contained in:
Mateusz Gruszczyński
2026-08-26 22:47:56 +02:00
parent f8d6bc2304
commit 584bdca7c6
11 changed files with 62 additions and 36 deletions
+12 -6
View File
@@ -314,9 +314,7 @@ function renderControlPlan() {
const target = zone.target_temperature == null ? '--' : Number(zone.target_temperature).toFixed(1);
const groupNames = zoneGroups.get(zone.zone_id) || [];
const scope = groupNames.length ? `${tr('groups.group')}: ${groupNames.join(' · ')}` : (zone.device_name || tr('common.noDevice'));
const planState = zone.device_manual_override
? tr('zones.manualDeviceControl')
: (zone.enabled ? (zone.demand ? tr('zones.requesting') : tr('zones.satisfied')) : tr('common.disabled'));
const planState = zoneRuntimeStatusLabel(zone, zone.mode || 'off');
return `<article class="panel plan-card plan-zone ${zone.enabled ? '' : 'disabled'}"><div class="plan-card-head"><div><span class="eyebrow">${esc(scope)}</span><h3>${esc(zone.zone_name)}</h3></div><span class="badge ${zone.device_manual_override ? 'manual-override' : (zone.enabled && zone.demand ? 'active' : '')}">${esc(planState)}</span></div><div class="plan-temp"><span>${fmtTemp(zone.current_temperature)}</span><b>→</b><strong>${esc(target)}<small>°C</small></strong></div><p>${esc(houseModeLabel(zone.mode || 'off'))} · ${esc(zonePresetLabel(zone.preset))}${zone.current_schedule_name ? ` · ${esc(zone.current_schedule_name)}` : ''}</p><ul class="plan-events">${events.length ? events.map(planEventMarkup).join('') : `<li class="muted">${esc(tr('plan.noEvents'))}</li>`}</ul></article>`;
}).join('');
@@ -686,6 +684,14 @@ function zonePresetLabel(preset) {
return tr(key) === key ? (preset || 'comfort') : tr(key);
}
function zoneRuntimeStatusLabel(zone, effectiveMode) {
if (zone.device_manual_override === true) return tr('zones.manualDeviceControl');
if (!zone.enabled) return tr('common.disabled');
if ((effectiveMode || 'off') === 'off') return tr('zones.waiting');
if (zone.current_temperature == null) return tr('zones.noMeasurement');
return zone.demand ? tr('zones.requesting') : tr('zones.satisfied');
}
function zoneCard(zone, detailed = true) {
const device = app.devices.find(d => d.id === zone.device_id);
const state = zone.enabled ? tr('common.active') : tr('common.disabled');
@@ -710,7 +716,7 @@ function zoneCard(zone, detailed = true) {
? `<div class="manual-override-panel"><div><strong>${esc(tr('zones.manualDeviceControl'))}</strong><p>${esc(tr('zones.manualDeviceDescription'))}</p></div><button type="button" data-action="zone-resume-automation" data-id="${esc(zone.id)}">${esc(tr('zones.resumeAutomation'))}</button></div>`
: '';
const manualPowerDisabled = !device || device.enabled === false ? ' disabled' : '';
const manualUnitPower = `<div class="zone-manual-power"><small title="${esc(tr('zones.unitPowerManualHint'))}">${esc(tr('zones.unitPowerManual'))}</small><div class="quick-control-row quick-control-row-2"><button class="${device?.power ? 'active' : ''}" data-action="zone-device-power" data-id="${esc(zone.id)}" data-value="true"${manualPowerDisabled}>${esc(tr('common.on'))}</button><button class="${device && !device.power ? 'active' : ''}" data-action="zone-device-power" data-id="${esc(zone.id)}" data-value="false"${manualPowerDisabled}>${esc(tr('common.off'))}</button></div></div>`;
const manualUnitPower = `<div class="zone-manual-power"><button type="button" class="zone-unit-power-toggle ${device?.power ? 'active' : ''}" title="${esc(tr('zones.unitPowerManualHint'))}" data-action="zone-device-power" data-id="${esc(zone.id)}" data-value="${device?.power ? 'false' : 'true'}" aria-pressed="${device?.power ? 'true' : 'false'}"${manualPowerDisabled}>${esc(tr(device?.power ? 'zones.turnUnitOff' : 'zones.turnUnitOn'))}</button></div>`;
if (detailed) {
const groupNames = (app.groups || []).filter(group => (group.zone_ids || []).includes(zone.id)).map(group => group.name);
@@ -720,7 +726,7 @@ function zoneCard(zone, detailed = true) {
<div class="list-card-head"><div><span class="eyebrow">${esc(tr('zones.configuration'))}</span><h3>${esc(zone.name)}</h3><p>${esc(device?.name || tr('common.noDevice'))} · ${esc(tr('groups.group'))}: ${esc(groupText)}</p></div><span class="badge ${zone.enabled ? 'active' : ''}">${esc(state)}</span></div>
<div class="zone-config-status">
<div class="zone-config-temperature"><small>${esc(tr('zones.currentStatus'))}</small><div><span>${fmtTemp(roomTemperature)}</span><b>→</b><strong>${Number.isFinite(target) ? `${target.toFixed(1)}°C` : '—'}</strong></div></div>
<div class="zone-config-runtime"><span class="badge ${zone.enabled && zone.demand ? 'active' : ''}">${esc(zone.enabled ? (zone.demand ? tr('zones.requesting') : tr('zones.satisfied')) : tr('common.disabled'))}</span><span>${esc(houseModeLabel(effectiveMode))} · ${esc(zonePresetLabel(zone.active_preset))}</span><small>${esc(override)}</small></div>
<div class="zone-config-runtime"><span class="badge ${zone.enabled && zone.demand ? 'active' : ''}">${esc(zoneRuntimeStatusLabel(zone, effectiveMode))}</span><span>${esc(houseModeLabel(effectiveMode))} · ${esc(zonePresetLabel(zone.active_preset))}</span><small>${esc(override)}</small></div>
</div>
<div class="zone-config-grid">
<div><small>${esc(tr('zones.modePolicy'))}</small><strong>${esc(policy)}</strong></div>
@@ -742,7 +748,7 @@ function zoneCard(zone, detailed = true) {
${['auto','comfort','sleep','away'].map(preset=>`<button class="${manual===preset?'active':''}" data-action="zone-preset" data-id="${esc(zone.id)}" data-value="${preset}">${esc(preset==='sleep'?tr('zones.sleepNow'):zonePresetLabel(preset))}</button>`).join('')}
</div>
<div class="mode-row zone-mode-row quick-control-row quick-control-row-3"><button class="${mode==='house'?'active':''}" data-action="zone-mode" data-id="${esc(zone.id)}" data-value="house">${esc(tr('zones.followHouseShort'))}</button><button class="${mode==='heat'?'active':''}" data-action="zone-mode" data-id="${esc(zone.id)}" data-value="heat">${esc(modeLabel('heat'))}</button><button class="${mode==='cool'?'active':''}" data-action="zone-mode" data-id="${esc(zone.id)}" data-value="cool">${esc(modeLabel('cool'))}</button></div>
<div class="zone-state-line"><span>${deviceManualOverride ? esc(tr('zones.manualDeviceControl')) : (zone.demand ? esc(tr('zones.requesting')) : esc(tr('zones.satisfied')))}</span><span>${esc(override)}</span></div>
<div class="zone-state-line"><span>${esc(zoneRuntimeStatusLabel(zone, effectiveMode))}</span><span>${esc(override)}</span></div>
${manualTakeover}
</article>`;
}
+3 -3
View File
@@ -780,9 +780,9 @@ body.simulation-standalone [data-view="simulation"] { min-height:calc(100vh - 36
.quick-device-control .temperature-control { gap:12px; padding:12px 0 10px; }
.quick-device-control .current-line { margin:-3px 0 10px; font-size:11px; }
.quick-device-control .device-toggles.quick-control-row { margin-top:1px; }
.quick-thermostat-control .zone-manual-power { margin-top:6px; }
.quick-thermostat-control .zone-manual-power > small { display:block; margin-bottom:2px; color:var(--muted); font-size:9px; }
.quick-thermostat-control .zone-manual-power button.active { color:var(--accent-text); background:var(--accent); font-weight:800; }
.quick-thermostat-control .zone-manual-power { display:flex; margin-top:6px; }
.quick-thermostat-control .zone-manual-power .zone-unit-power-toggle { width:100%; min-height:30px; font-size:10px; }
.quick-thermostat-control .zone-manual-power .zone-unit-power-toggle.active { color:var(--accent-text); background:var(--accent); font-weight:800; }
.quick-thermostat-control .thermostat-main { margin:8px 0 7px; }
.quick-thermostat-control .zone-enable-toggle { min-height:28px; padding:4px 8px; font-size:10px; }
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'gree-controller-v077-mode-label-fit';
const CACHE = 'gree-controller-v078-zone-status-unit-power';
const SCOPE = new URL(self.registration.scope).pathname.replace(/\/$/, '');
const path = value => `${SCOPE}${value.startsWith('/') ? value : `/${value}`}` || '/';
const ASSETS = [path('/'), path('/styles.css'), path('/app.js'), path('/theme-init.js'), path('/favicon.svg'), path('/manifest.webmanifest'), path('/lang/index.json'), path('/lang/en.json')];