v0.7.12
This commit is contained in:
+24
-1
@@ -47,6 +47,25 @@ const modeLabel = mode => tr(`mode.${mode}`) === `mode.${mode}` ? mode : tr(`mod
|
||||
const houseModeLabel = mode => mode === 'off' ? tr('house.noControl') : modeLabel(mode);
|
||||
const fanLabel = value => ({0:'fan.auto',1:'fan.low',2:'fan.mediumLow',3:'fan.medium',4:'fan.mediumHigh',5:'fan.high'}[value] ? tr({0:'fan.auto',1:'fan.low',2:'fan.mediumLow',3:'fan.medium',4:'fan.mediumHigh',5:'fan.high'}[value]) : value);
|
||||
const dateTime = value => value ? new Intl.DateTimeFormat(locale(), {dateStyle:'short', timeStyle:'short'}).format(new Date(value)) : '—';
|
||||
const localResumeSeconds = value => {
|
||||
const timestamp = value ? new Date(value).getTime() : NaN;
|
||||
return Number.isFinite(timestamp) ? Math.max(0, Math.ceil((timestamp - Date.now()) / 1000)) : null;
|
||||
};
|
||||
const formatCountdown = seconds => {
|
||||
if (!Number.isFinite(seconds)) return '--:--';
|
||||
const safe = Math.max(0, Math.floor(seconds));
|
||||
const minutes = Math.floor(safe / 60);
|
||||
const remainder = safe % 60;
|
||||
return `${String(minutes).padStart(2,'0')}:${String(remainder).padStart(2,'0')}`;
|
||||
};
|
||||
function updateLocalThermostatCountdowns() {
|
||||
$$('[data-local-resume-countdown]').forEach(node => {
|
||||
const remaining = localResumeSeconds(node.dataset.localResumeCountdown);
|
||||
node.textContent = remaining !== null && remaining > 0
|
||||
? tr('zones.localThermostatOffDescriptionTimed', {time:formatCountdown(remaining)})
|
||||
: tr('zones.localThermostatResuming');
|
||||
});
|
||||
}
|
||||
const haSensorLabel = entity => app.sensorAliases?.[entity] || app.settings?.home_assistant?.sensor_aliases?.[entity] || entity;
|
||||
|
||||
function updateConnectionIndicator(status) {
|
||||
@@ -713,6 +732,7 @@ function zoneCard(zone, detailed = true) {
|
||||
const hasManualOverride = zone.manual_preset != null || zone.manual_setpoint != null;
|
||||
const deviceManualOverride = zone.device_manual_override === true;
|
||||
const localThermostatPower = zone.local_thermostat_power;
|
||||
const localThermostatResumeAt = zone.local_thermostat_resume_at || null;
|
||||
const localThermostatOverride = localThermostatPower === true || localThermostatPower === false;
|
||||
const override = deviceManualOverride
|
||||
? (zone.device_manual_override_until
|
||||
@@ -726,7 +746,9 @@ function zoneCard(zone, detailed = true) {
|
||||
const manualTakeover = deviceManualOverride
|
||||
? `<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-resume="device" data-id="${esc(zone.id)}">${esc(tr('zones.resumeAutomation'))}</button></div>`
|
||||
: localThermostatOverride
|
||||
? `<div class="manual-override-panel local-thermostat-panel"><div><strong>${esc(tr('zones.localThermostatControl'))}</strong><p>${esc(tr(localThermostatPower ? 'zones.localThermostatOnDescription' : 'zones.localThermostatOffDescription'))}</p></div><button type="button" data-action="zone-resume-automation" data-resume="local" data-id="${esc(zone.id)}">${esc(tr('zones.resumeAutomation'))}</button></div>`
|
||||
? `<div class="manual-override-panel local-thermostat-panel"><div><strong>${esc(tr('zones.localThermostatControl'))}</strong>${localThermostatPower === false && localThermostatResumeAt
|
||||
? `<p data-local-resume-countdown="${esc(localThermostatResumeAt)}">${esc(tr('zones.localThermostatOffDescriptionTimed', {time:formatCountdown(localResumeSeconds(localThermostatResumeAt))}))}</p>`
|
||||
: `<p>${esc(tr(localThermostatPower ? 'zones.localThermostatOnDescription' : 'zones.localThermostatOffDescription'))}</p>`}</div><button type="button" data-action="zone-resume-automation" data-resume="local" data-id="${esc(zone.id)}">${esc(tr(localThermostatPower === false ? 'zones.resumeNow' : 'zones.resumeAutomation'))}</button></div>`
|
||||
: '';
|
||||
const localPowerDisabled = !device || device.enabled === false ? ' disabled' : '';
|
||||
const localRequestedOn = localThermostatPower === true ? true : (localThermostatPower === false ? false : !!device?.power);
|
||||
@@ -2223,4 +2245,5 @@ async function startApplication() {
|
||||
if (location.pathname === '/' || location.pathname === `${APP_BASE}/`) updateBrowserUrl('/dashboard', true);
|
||||
}
|
||||
|
||||
setInterval(updateLocalThermostatCountdowns, 1000);
|
||||
startApplication().catch(error => console.error('Application startup failed:', error));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const CACHE = 'gree-controller-v0711-clean-local-thermostat';
|
||||
const CACHE = 'gree-controller-v0712-timed-local-resume';
|
||||
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')];
|
||||
|
||||
Reference in New Issue
Block a user