v0.5.4
This commit is contained in:
+21
-4
@@ -369,6 +369,7 @@ function buildZoneSimulation(zone, planZone) {
|
||||
const quiet = nightActive && app.settings?.night_mode?.force_quiet
|
||||
? tr('simulation.quietIfSupported')
|
||||
: (zone?.smart_fan ? (!demand ? tr('simulation.quietIfSupported') : tr('common.off')) : tr('simulation.manual'));
|
||||
const nativeSleep = nightActive && app.settings?.night_mode?.use_native_sleep && device?.supports_sleep === true;
|
||||
const reasoning = !zone?.enabled || planZone?.enabled === false
|
||||
? tr('simulation.reasonDisabled')
|
||||
: mode === 'off'
|
||||
@@ -378,7 +379,7 @@ function buildZoneSimulation(zone, planZone) {
|
||||
: demand
|
||||
? tr('simulation.reasonDemand', {mode: modeLabel(mode), target: target.toFixed(1), hysteresis: hysteresis.toFixed(1)})
|
||||
: tr('simulation.reasonSatisfied', {target: target.toFixed(1), standby: standbyTarget.toFixed(1)});
|
||||
return {device, mode, current, target, demand, status, outdoor, hysteresis, assist, activeTarget, standbyTarget, desiredDeviceTarget, fanSpeed, quiet, reasoning};
|
||||
return {device, mode, current, target, demand, status, outdoor, hysteresis, assist, activeTarget, standbyTarget, desiredDeviceTarget, fanSpeed, quiet, nativeSleep, reasoning};
|
||||
}
|
||||
|
||||
function simulationRuleAction(rule) {
|
||||
@@ -450,7 +451,8 @@ function renderSimulationPage() {
|
||||
nodes.push(node({left:x.sensor,top:y,kind:'input',eyebrow:tr('simulation.stepRoom'),title:sensorName,value:fmtTemp(sim.current),meta:source,badge:'●',badgeClass:sim.current == null?'':'active'}));
|
||||
nodes.push(node({left:x.thermostat,top:y,kind:'logic',eyebrow:tr('simulation.thermostat'),title:planZone.zone_name,value:sim.target == null?'—':fmtTemp(sim.target),meta:`${zonePresetLabel(planZone.preset)} · ${tr('simulation.hysteresis',{value:sim.hysteresis.toFixed(1)})}`,badge:modeLabel(sim.mode)}));
|
||||
nodes.push(node({left:x.decision,top:y,kind:`logic decision ${sim.demand?'demand':'satisfied'}`,eyebrow:tr('simulation.stepDecision'),title:status.label,value:sim.demand?tr('simulation.callForComfort'):tr('simulation.standby'),meta:sim.reasoning,badge:sim.demand?'▶':'✓',badgeClass:status.badge}));
|
||||
nodes.push(node({left:x.unit,top:y,kind:'action',eyebrow:tr('simulation.stepCommand'),title:planZone.device_name || tr('common.device'),value:command,meta:`${tr('devices.quiet')}: ${quietText}`,badge:sim.demand?'RUN':'IDLE',badgeClass:sim.demand?'active':''}));
|
||||
const sleepMeta = sim.nativeSleep ? ` · ${tr('devices.sleep')}: ${tr('common.on')}` : '';
|
||||
nodes.push(node({left:x.unit,top:y,kind:'action',eyebrow:tr('simulation.stepCommand'),title:planZone.device_name || tr('common.device'),value:command,meta:`${tr('devices.quiet')}: ${quietText}${sleepMeta}`,badge:sim.demand?'RUN':'IDLE',badgeClass:sim.demand?'active':''}));
|
||||
nodes.push(node({left:x.event,top:y,kind:'event',eyebrow:tr('simulation.nextEvent'),title:eventValue,value:next?.preset ? zonePresetLabel(next.preset) : tr('simulation.schedule'),meta:eventMeta,badge:'›'}));
|
||||
|
||||
links.push(pathBetween(x.sensor+nodeW,mid,x.thermostat,mid,'input-link'));
|
||||
@@ -488,6 +490,18 @@ function scheduleControlPlanLoad() {
|
||||
app.controlPlanTimer = setTimeout(loadControlPlan, 180);
|
||||
}
|
||||
|
||||
function deviceFeaturePanel(device) {
|
||||
const features = [
|
||||
['light', 'supports_light', tr('devices.light')],
|
||||
['xfan', 'supports_xfan', tr('devices.xfan')],
|
||||
['health', 'supports_health', tr('devices.health')],
|
||||
['air', 'supports_air', tr('devices.air')],
|
||||
['sleep', 'supports_sleep', tr('devices.sleep')],
|
||||
].filter(([, support]) => device[support] === true);
|
||||
if (!features.length) return `<div class="device-capability-panel"><small>${esc(tr('devices.features'))}</small><span class="muted">${esc(tr('devices.noExtraFeatures'))}</span></div>`;
|
||||
return `<div class="device-capability-panel"><small>${esc(tr('devices.features'))}</small><div class="device-capability-buttons">${features.map(([field,,label]) => `<button class="${device[field] ? 'active' : ''}" data-action="toggle" data-field="${field}" data-device="${esc(device.id)}">${esc(label)}</button>`).join('')}</div></div>`;
|
||||
}
|
||||
|
||||
function deviceCard(device, detailed = false) {
|
||||
const modes = ['auto','cool','dry','fan','heat'];
|
||||
const fans = [0,1,3,5];
|
||||
@@ -509,9 +523,10 @@ function deviceCard(device, detailed = false) {
|
||||
<div class="fan-row">${fans.map(fan => `<button class="${Number(device.fan_speed) === fan ? 'active' : ''}" data-action="fan" data-value="${fan}" data-device="${esc(device.id)}">${esc(fanLabel(fan))}</button>`).join('')}</div>
|
||||
<div class="device-toggles">
|
||||
<button class="${device.swing_vertical ? 'active' : ''}" data-action="toggle" data-field="swing_vertical" data-device="${esc(device.id)}">↕ ${esc(tr('devices.swing'))}</button>
|
||||
<button class="${device.quiet ? 'active' : ''}" data-action="toggle" data-field="quiet" data-device="${esc(device.id)}">${esc(tr('devices.quiet'))}</button>
|
||||
<button class="${device.turbo ? 'active' : ''}" data-action="toggle" data-field="turbo" data-device="${esc(device.id)}">${esc(tr('devices.turbo'))}</button>
|
||||
${device.supports_quiet === false ? '' : `<button class="${device.quiet ? 'active' : ''}" data-action="toggle" data-field="quiet" data-device="${esc(device.id)}">${esc(tr('devices.quiet'))}</button>`}
|
||||
${device.supports_turbo === false ? '' : `<button class="${device.turbo ? 'active' : ''}" data-action="toggle" data-field="turbo" data-device="${esc(device.id)}">${esc(tr('devices.turbo'))}</button>`}
|
||||
</div>
|
||||
${detailed ? deviceFeaturePanel(device) : ''}
|
||||
${detailed ? `<div class="card-footer">${error}<div class="card-menu"><button data-action="poll" data-device="${esc(device.id)}">${esc(tr('actions.read'))}</button><button data-action="rename-device" data-device="${esc(device.id)}">${esc(tr('devices.nameProtocol'))}</button>${device.simulated ? '' : `<button data-action="bind" data-device="${esc(device.id)}">${esc(tr('actions.bind'))}</button>`}<button class="danger" data-action="delete-device" data-device="${esc(device.id)}">${esc(tr('actions.delete'))}</button></div></div>` : ''}
|
||||
</article>`;
|
||||
}
|
||||
@@ -663,6 +678,7 @@ function renderSettings() {
|
||||
form.night_mode_end.value = app.settings.night_mode?.end_time || '06:00';
|
||||
form.night_mode_max_fan_speed.value = String(app.settings.night_mode?.max_fan_speed || 1);
|
||||
form.night_mode_force_quiet.checked = app.settings.night_mode?.force_quiet !== false;
|
||||
form.night_mode_native_sleep.checked = app.settings.night_mode?.use_native_sleep !== false;
|
||||
form.influx_enabled.checked = !!app.settings.influxdb?.enabled;
|
||||
form.influx_version.value = String(app.settings.influxdb?.version || '2');
|
||||
form.influx_threshold_days.value = app.settings.influxdb?.history_threshold_days || 30;
|
||||
@@ -1460,6 +1476,7 @@ function settingsBodyFromForm(form) {
|
||||
night_mode:{
|
||||
enabled:form.night_mode_enabled.checked,start_time:raw.night_mode_start,end_time:raw.night_mode_end,
|
||||
max_fan_speed:Number(raw.night_mode_max_fan_speed),force_quiet:form.night_mode_force_quiet.checked,
|
||||
use_native_sleep:form.night_mode_native_sleep.checked,
|
||||
},
|
||||
influxdb:{
|
||||
enabled:form.influx_enabled.checked, version:raw.influx_version, url:raw.influx_url,
|
||||
|
||||
Reference in New Issue
Block a user