v0.12.0-preety_code

This commit is contained in:
Mateusz Gruszczyński
2026-09-03 15:33:37 +02:00
parent be67932b47
commit 07be4b85d9
87 changed files with 11691 additions and 3172 deletions
+295 -90
View File
@@ -130,7 +130,8 @@
<div class="dashboard-section-head compact-head">
<div><span class="eyebrow" data-i18n="nav.devices">Devices</span>
<h2 data-i18n="dashboard.quickControl">Manual control</h2>
<p data-i18n="dashboard.manualControlHint">Direct GREE control: power, temperature, mode, fan and supported unit functions.</p>
<p data-i18n="dashboard.manualControlHint">Direct GREE control: power, temperature, mode, fan and
supported unit functions.</p>
</div>
<span class="badge" id="dashboardDeviceCount">0</span>
</div>
@@ -148,7 +149,8 @@
data-i18n="actions.discover">Discover</button><button class="secondary" data-open="deviceDialog"
data-i18n="devices.addManual">Add manually</button></div>
</div>
<p class="lead" data-i18n="devices.technicalDescription">Technical configuration and diagnostics only. Current operating settings are available in Manual control.</p>
<p class="lead" data-i18n="devices.technicalDescription">Technical configuration and diagnostics only. Current
operating settings are available in Manual control.</p>
<div class="device-grid" id="deviceList"></div>
</section>
@@ -182,7 +184,10 @@
<div class="section-heading">
<div><span class="eyebrow" data-i18n="flow.eyebrow">Visual logic</span>
<h1 data-i18n="nav.flows">Flow</h1>
</div><div class="section-actions flow-page-actions"><button class="secondary" type="button" data-action="import-flow" data-i18n="flow.import">Import Flow</button><button class="primary" type="button" data-action="new-flow" data-i18n="flow.new">New Flow</button></div>
</div>
<div class="section-actions flow-page-actions"><button class="secondary" type="button" data-action="import-flow"
data-i18n="flow.import">Import Flow</button><button class="primary" type="button" data-action="new-flow"
data-i18n="flow.new">New Flow</button></div>
</div>
<nav class="automation-tabs" data-i18n-aria="automationHub.navigation" aria-label="Automation navigation">
<button type="button" class="active" data-go="flows" data-i18n="nav.flows">Flow</button>
@@ -191,8 +196,11 @@
</nav>
<div class="panel flow-info-panel">
<div><strong data-i18n="flow.infoTitle">One place for schedules and automations</strong>
<p data-i18n="flow.infoText">Build the logic from blocks. GREE Controller translates Flow into generated schedules and automations. Generated entries are read-only outside this editor.</p>
<button type="button" class="secondary flow-shared-settings-link" data-action="flow-shared-input-settings" data-i18n="flow.sharedInputsSettingsLink">Wspólne wejścia Flow w Home Assistant →</button></div>
<p data-i18n="flow.infoText">Build the logic from blocks. GREE Controller translates Flow into generated
schedules and automations. Generated entries are read-only outside this editor.</p>
<button type="button" class="secondary flow-shared-settings-link" data-action="flow-shared-input-settings"
data-i18n="flow.sharedInputsSettingsLink">Wspólne wejścia Flow w Home Assistant →</button>
</div>
<span class="badge" data-i18n="flow.sourceOfTruth">Flow = source of truth</span>
</div>
<section class="flow-list-section">
@@ -390,46 +398,99 @@
tokens for the Home Assistant integration.</p>
<form class="settings-form standalone-settings-form" id="homeAssistantForm">
<section class="panel settings-block">
<div class="settings-block-head"><div><h3 data-i18n="settings.haConnection">Połączenie z Home Assistant</h3><p data-i18n="settings.haConnectionHint">Adres serwera i dane dostępu używane przez wszystkie funkcje Home Assistant.</p></div></div>
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.haConnection">Połączenie z Home Assistant</h3>
<p data-i18n="settings.haConnectionHint">Adres serwera i dane dostępu używane przez wszystkie funkcje Home
Assistant.</p>
</div>
</div>
<div class="settings-grid">
<label class="wide"><span>URL</span><input type="url" name="ha_url" placeholder="http://homeassistant.local:8123"></label>
<label class="wide"><span data-i18n="settings.haLongLivedToken">Long-Lived Access Token</span><input type="password" name="ha_token" autocomplete="new-password" data-i18n-placeholder="settings.haTokenKeep" placeholder="Leave empty to keep the saved token"></label>
<label class="check wide"><input type="checkbox" name="ha_allow_invalid_tls"> <span data-i18n="settings.allowInvalidTls">Allow invalid/self-signed HTTPS certificate</span></label>
<p class="field-note wide warning-note" data-i18n="settings.allowInvalidTlsHint">Use only for a trusted local Home Assistant server.</p>
<div class="form-actions wide"><button type="button" class="secondary" id="haTest" data-i18n="settings.testHa">Test HA</button></div>
<label class="wide"><span>URL</span><input type="url" name="ha_url"
placeholder="http://homeassistant.local:8123"></label>
<label class="wide"><span data-i18n="settings.haLongLivedToken">Long-Lived Access Token</span><input
type="password" name="ha_token" autocomplete="new-password" data-i18n-placeholder="settings.haTokenKeep"
placeholder="Leave empty to keep the saved token"></label>
<label class="check wide"><input type="checkbox" name="ha_allow_invalid_tls"> <span
data-i18n="settings.allowInvalidTls">Allow invalid/self-signed HTTPS certificate</span></label>
<p class="field-note wide warning-note" data-i18n="settings.allowInvalidTlsHint">Use only for a trusted
local Home Assistant server.</p>
<div class="form-actions wide"><button type="button" class="secondary" id="haTest"
data-i18n="settings.testHa">Test HA</button></div>
</div>
</section>
<section class="panel settings-block">
<div class="settings-block-head"><div><h3 data-i18n="settings.haThermostatSources">Źródła temperatury sterowania</h3><p data-i18n="settings.haThermostatSourcesHint">Te ustawienia należą do logiki termostatów i źródeł temperatury, nie do wspólnych wejść Flow.</p></div></div>
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.haThermostatSources">Źródła temperatury sterowania</h3>
<p data-i18n="settings.haThermostatSourcesHint">Te ustawienia należą do logiki termostatów i źródeł
temperatury, nie do wspólnych wejść Flow.</p>
</div>
</div>
<div class="settings-grid">
<label class="wide"><span data-i18n="settings.defaultEntity">Connection test entity_id</span><input name="ha_entity_id" placeholder="sensor.living_room_temperature"></label>
<p class="field-note wide" data-i18n="settings.defaultEntityHint">This entity is used by the Home Assistant connection test when no other entity is specified. It is not automatically used as a zone temperature source.</p>
<label class="wide"><span data-i18n="settings.outdoorEntity">Outdoor temperature entity_id</span><input name="ha_outdoor_entity_id" placeholder="sensor.outdoor_temperature"></label>
<label class="wide"><span data-i18n="settings.haSensorStaleAfterMinutes">Maximum HA sensor reading age (min)</span><input type="number" name="ha_sensor_stale_after_minutes" min="1" max="1440" step="1" value="5"></label>
<p class="field-note wide" data-i18n="settings.haSensorStaleAfterHint">If the HA sensor is not updated within this time, the reading is treated as stale.</p>
<label class="check wide"><input type="checkbox" name="outdoor_assist_enabled"> <span data-i18n="settings.outdoorAssist">Use outdoor temperature as smart-control assist</span></label>
<label class="wide"><span data-i18n="settings.defaultEntity">Connection test entity_id</span><input
name="ha_entity_id" placeholder="sensor.living_room_temperature"></label>
<p class="field-note wide" data-i18n="settings.defaultEntityHint">This entity is used by the Home Assistant
connection test when no other entity is specified. It is not automatically used as a zone temperature
source.</p>
<label class="wide"><span data-i18n="settings.outdoorEntity">Outdoor temperature entity_id</span><input
name="ha_outdoor_entity_id" placeholder="sensor.outdoor_temperature"></label>
<label class="wide"><span data-i18n="settings.haSensorStaleAfterMinutes">Maximum HA sensor reading age
(min)</span><input type="number" name="ha_sensor_stale_after_minutes" min="1" max="1440" step="1"
value="5"></label>
<p class="field-note wide" data-i18n="settings.haSensorStaleAfterHint">If the HA sensor is not updated
within this time, the reading is treated as stale.</p>
<label class="check wide"><input type="checkbox" name="outdoor_assist_enabled"> <span
data-i18n="settings.outdoorAssist">Use outdoor temperature as smart-control assist</span></label>
</div>
</section>
<section class="panel settings-block flow-shared-settings" id="flowSharedInputsSettings">
<div class="settings-block-head flow-shared-settings-head"><div><h3 data-i18n="flow.sharedInputsTitle">Wspólne wejścia Flow</h3><p data-i18n="flow.sharedInputsHint">Zdefiniuj wspólne źródła wartości raz i używaj ich w wielu Flow. Czujniki HA dodane tylko tutaj nie są zapisywane do metryk.</p></div><button type="button" class="primary flow-shared-add-button" id="addFlowSharedInput" data-i18n="flow.sharedInputAdd">Dodaj wejście</button></div>
<input type="hidden" id="flowSharedInputsRevision" name="flow_inputs_revision" value="[]"><div id="flowSharedInputList" class="flow-shared-input-list"></div>
<div class="settings-block-head flow-shared-settings-head">
<div>
<h3 data-i18n="flow.sharedInputsTitle">Wspólne wejścia Flow</h3>
<p data-i18n="flow.sharedInputsHint">Zdefiniuj wspólne źródła wartości raz i używaj ich w wielu Flow.
Czujniki HA dodane tylko tutaj nie są zapisywane do metryk.</p>
</div><button type="button" class="primary flow-shared-add-button" id="addFlowSharedInput"
data-i18n="flow.sharedInputAdd">Dodaj wejście</button>
</div>
<input type="hidden" id="flowSharedInputsRevision" name="flow_inputs_revision" value="[]">
<div id="flowSharedInputList" class="flow-shared-input-list"></div>
</section>
<section class="panel settings-block">
<div class="settings-block-head"><div><h3 data-i18n="settings.sensorAliases">Sensor aliases</h3><p data-i18n="settings.sensorAliasesHint">Badges show whether an entity is collected as metrics, used by Flow, or both.</p></div></div>
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.sensorAliases">Sensor aliases</h3>
<p data-i18n="settings.sensorAliasesHint">Badges show whether an entity is collected as metrics, used by
Flow, or both.</p>
</div>
</div>
<div class="sensor-alias-manager">
<div id="sensorAliasList" class="sensor-alias-list"></div>
<div class="sensor-alias-add"><input id="sensorAliasEntity" placeholder="sensor.gabinet_temperature"><input id="sensorAliasName" data-i18n-placeholder="settings.aliasPlaceholder" placeholder="Gabinet"><button type="button" class="secondary" id="addSensorAlias" data-i18n="actions.add">Add</button></div>
<div class="sensor-alias-add"><input id="sensorAliasEntity" placeholder="sensor.gabinet_temperature"><input
id="sensorAliasName" data-i18n-placeholder="settings.aliasPlaceholder" placeholder="Gabinet"><button
type="button" class="secondary" id="addSensorAlias" data-i18n="actions.add">Add</button></div>
</div>
</section>
<section class="panel settings-block">
<div class="settings-block-head"><div><h3 data-i18n="settings.haIntegrationAccess">Home Assistant integration access</h3><p data-i18n="settings.haIntegrationHint">Create a controller token and paste it into the GREE Controller integration in Home Assistant.</p></div></div>
<div class="token-manager"><div id="accessTokenList" class="token-list"></div><div class="form-actions"><button type="button" class="primary" id="createAccessToken" data-i18n="settings.newToken">Create new token</button></div></div>
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.haIntegrationAccess">Home Assistant integration access</h3>
<p data-i18n="settings.haIntegrationHint">Create a controller token and paste it into the GREE Controller
integration in Home Assistant.</p>
</div>
</div>
<div class="token-manager">
<div id="accessTokenList" class="token-list"></div>
<div class="form-actions"><button type="button" class="primary" id="createAccessToken"
data-i18n="settings.newToken">Create new token</button></div>
</div>
</section>
<div class="settings-save-bar"><span data-i18n="homeAssistant.saveHint">Save Home Assistant and sensor changes.</span><button class="primary" type="submit" data-i18n="actions.save">Save</button></div>
<div class="settings-save-bar"><span data-i18n="homeAssistant.saveHint">Save Home Assistant and sensor
changes.</span><button class="primary" type="submit" data-i18n="actions.save">Save</button></div>
</form>
</section>
@@ -710,58 +771,155 @@
<section id="flowEditor" class="flow-editor" hidden aria-label="Flow editor">
<header class="flow-editor-bar">
<div class="flow-editor-title"><button type="button" class="icon-button" data-action="close-flow-editor" aria-label="Back"></button><div><span class="eyebrow" data-i18n="flow.editorEyebrow">Flow editor</span><div class="flow-name-wrap"><div id="flowNameView" class="flow-name-view" hidden><button id="flowNameText" class="flow-name-text" type="button" data-action="edit-flow-name" data-i18n-title="flow.editName" title="Edit Flow name"></button><button class="flow-name-edit" type="button" data-action="edit-flow-name" data-i18n-title="flow.editName" data-i18n-aria="flow.editName" title="Edit Flow name" aria-label="Edit Flow name"></button></div><input id="flowName" maxlength="100" data-i18n-placeholder="flow.namePlaceholder" data-i18n-title="flow.nameAliasHint" placeholder="My automation"></div></div></div>
<div class="flow-editor-actions"><button class="secondary flow-desktop-action" type="button" data-action="flow-templates" data-i18n="flow.templates">Templates</button><button class="secondary flow-desktop-action" type="button" data-action="import-flow" data-i18n="flow.import">Import</button><button class="secondary flow-desktop-action" type="button" data-action="export-flow" data-i18n="flow.export">Export</button><button class="secondary flow-desktop-action" type="button" data-action="flow-dry-run" data-i18n="flow.dryRun">Dry-run</button><button class="secondary flow-desktop-action" type="button" data-action="flow-logs" data-i18n="flow.logs">Logs</button><label class="flow-enabled"><input type="checkbox" id="flowEnabled" checked><span id="flowEnabledLabel" data-i18n="common.enabled">Enabled</span></label><span id="flowSaveStatus" class="flow-save-status" aria-live="polite"></span><span id="flowCompileStatus" class="badge flow-compile-status"></span><button class="secondary flow-mobile-actions-button" type="button" data-action="flow-mobile-actions" data-i18n="flow.actions">Actions</button></div>
<button class="primary flow-save-button" type="button" data-action="save-flow" data-i18n="actions.save">Save</button>
</header>
<div class="flow-editor-body">
<aside class="flow-palette">
<div class="flow-palette-head"><strong data-i18n="flow.blocks">Blocks</strong><small data-i18n="flow.paletteHint">Add a block, then connect its output to the next block.</small></div>
<div class="flow-palette-group flow-palette-trigger"><span data-i18n="flow.triggers">Wyzwalacze</span>
<button type="button" data-flow-add="cron_trigger" data-i18n="flow.node.cronTrigger">CRON</button></div>
<div class="flow-palette-group flow-palette-time"><span data-i18n="flow.time">Czas</span>
<button type="button" data-flow-add="weekday" data-i18n="flow.node.weekday">Dni tygodnia</button><button type="button" data-flow-add="time_range" data-i18n="flow.node.timeRange">Przedział godzin</button><button type="button" data-flow-add="date_range" data-i18n="flow.node.dateRange">Zakres dat</button><button type="button" data-flow-add="night_mode" data-i18n="flow.node.nightMode">Tryb nocny</button></div>
<div class="flow-palette-group flow-palette-timeop"><span data-i18n="flow.timeOps">Operacje czasu</span>
<button type="button" data-flow-add="stable_for" data-i18n="flow.node.stableFor">Utrzymuje się przez…</button><button type="button" data-flow-add="state_duration" data-i18n="flow.node.stateDuration">Czas trwania stanu</button><button type="button" data-flow-add="on_change" data-i18n="flow.node.onChange">Tylko przy zmianie</button><button type="button" data-flow-add="rate_limit" data-i18n="flow.node.rateLimit">Maks. X razy / okres</button><button type="button" data-flow-add="delay" data-i18n="flow.node.delay">Odczekaj…</button></div>
<div class="flow-palette-group flow-palette-sensor"><span data-i18n="flow.sensors">Sensory / wartości</span>
<button type="button" data-flow-add="outdoor_temperature" data-i18n="flow.node.outdoorTemperature">Temperatura zewn.</button><button type="button" data-flow-add="device_temperature" data-i18n="flow.node.deviceTemperature">Temperatura urządzenia</button><button type="button" data-flow-add="zone_temperature" data-i18n="flow.node.zoneTemperature">Temperatura strefy</button><button type="button" data-flow-add="house_mode" data-i18n="flow.node.houseMode">Tryb domu</button><button type="button" data-flow-add="device_state" data-i18n="flow.node.deviceState">Stan urządzenia</button><button type="button" data-flow-add="zone_state" data-i18n="flow.node.zoneState">Stan termostatu</button><button type="button" data-flow-add="group_state" data-i18n="flow.node.groupState">Stan grupy</button><button type="button" data-flow-add="ha_state" data-i18n="flow.node.haState">HA: stan</button><button type="button" data-flow-add="ha_numeric" data-i18n="flow.node.haNumeric">HA: wartość</button><button type="button" data-flow-add="ha_attribute" data-i18n="flow.node.haAttribute">HA: atrybut</button><button type="button" data-flow-add="ha_available" data-i18n="flow.node.haAvailable">HA: dostępność</button><button type="button" data-flow-add="constant" data-i18n="flow.node.constant">Stała testowa</button><button type="button" data-flow-add="shared_input" data-i18n="flow.node.sharedInput">Wspólne wejście</button><button type="button" data-flow-add="rolling_stat" data-i18n="flow.node.rollingStat">Średnia / mediana</button><button type="button" data-flow-add="oscillates" data-i18n="flow.node.oscillates">Wartość oscyluje</button></div>
<div class="flow-palette-group flow-palette-logic"><span data-i18n="flow.logic">Logika</span><button type="button" data-flow-add="logic_and" data-i18n="flow.node.and">AND</button><button type="button" data-flow-add="logic_or" data-i18n="flow.node.or">OR</button><button type="button" data-flow-add="logic_not" data-i18n="flow.node.not">NOT</button></div>
<div class="flow-palette-group flow-palette-action"><span data-i18n="flow.actions">Akcje</span>
<button type="button" data-flow-add="zone_thermostat" data-i18n="flow.node.thermostat">Termostat</button><button type="button" data-flow-add="device_action" data-i18n="flow.node.greeDevice">Urządzenie GREE</button><button type="button" data-flow-add="group_action" data-i18n="flow.node.group">Grupa</button></div>
<div class="flow-palette-group flow-palette-haaction"><span data-i18n="flow.haActions">Home Assistant</span>
<button type="button" data-flow-add="ha_service_action" data-i18n="flow.node.haServiceAction">Home Assistant: usługa</button></div>
</aside>
<div class="flow-workspace-wrap">
<div class="flow-workspace-toolbar"><div class="flow-workspace-primary-actions"><button type="button" class="primary flow-add-block-button" data-action="flow-add-block"><span aria-hidden="true"></span><span data-i18n="flow.addBlock">Add block</span></button><button type="button" class="secondary flow-selection-action" data-action="flow-select-all" data-i18n="flow.selectAll">Zaznacz wszystko</button><button type="button" class="secondary flow-selection-action" data-action="flow-clear-selection" data-i18n="flow.clearSelection">Wyczyść zaznaczenie</button><span id="flowSelectionCount" class="badge"></span></div><div class="flow-zoom-controls" role="group" data-i18n-aria="flow.zoomControls" aria-label="Canvas zoom"><button type="button" class="secondary icon-button" data-action="flow-zoom-out" data-i18n-title="flow.zoomOut" title="Zoom out"></button><span id="flowZoomLabel" aria-live="polite">100%</span><button type="button" class="secondary icon-button" data-action="flow-zoom-in" data-i18n-title="flow.zoomIn" title="Zoom in"></button><button type="button" class="secondary flow-fit-button" data-action="flow-fit" data-i18n="flow.fitView">Fit</button></div></div>
<div id="flowWorkspace" class="flow-workspace" tabindex="0">
<div id="flowCanvas" class="flow-canvas"><svg id="flowEdges" class="flow-edges" aria-hidden="true"></svg><div id="flowNodes" class="flow-nodes"></div></div>
<div id="flowEmptyHint" class="flow-empty-hint"><strong data-i18n="flow.emptyCanvas">Start by adding blocks</strong><span data-i18n="flow.emptyCanvasHint">Conditions go on the left, actions on the right.</span><button type="button" class="primary" data-action="flow-add-block" data-i18n="flow.addBlock">Add block</button></div>
</div>
<div class="flow-natural-preview" id="flowNaturalPreview">
<button type="button" class="flow-preview-toggle" data-action="flow-preview-toggle" aria-expanded="false"><strong data-i18n="flow.interpretation">Interpretation</strong><span class="flow-preview-toggle-icon" aria-hidden="true"></span></button>
<div class="flow-preview-details">
<div class="flow-preview-item flow-preview-interpretation"><strong data-i18n="flow.interpretation">Interpretation</strong><span id="flowInterpretation"></span></div>
<div class="flow-preview-item flow-preview-runtime" id="flowRuntimeInfo"><strong data-i18n="flow.runtimeInfo">Flow cycle</strong><span id="flowRuntimeSummary"></span></div>
<div class="flow-editor-title"><button type="button" class="icon-button" data-action="close-flow-editor"
aria-label="Back"></button>
<div><span class="eyebrow" data-i18n="flow.editorEyebrow">Flow editor</span>
<div class="flow-name-wrap">
<div id="flowNameView" class="flow-name-view" hidden><button id="flowNameText" class="flow-name-text"
type="button" data-action="edit-flow-name" data-i18n-title="flow.editName"
title="Edit Flow name"></button><button class="flow-name-edit" type="button"
data-action="edit-flow-name" data-i18n-title="flow.editName" data-i18n-aria="flow.editName"
title="Edit Flow name" aria-label="Edit Flow name"></button></div><input id="flowName" maxlength="100"
data-i18n-placeholder="flow.namePlaceholder" data-i18n-title="flow.nameAliasHint"
placeholder="My automation">
</div>
</div>
</div>
<aside id="flowInspector" class="flow-inspector"><div class="empty compact"><strong data-i18n="flow.selectBlock">Select a block</strong><span data-i18n="flow.selectBlockHint">Its settings will appear here.</span></div></aside>
<div class="flow-editor-actions"><button class="secondary flow-desktop-action" type="button"
data-action="flow-templates" data-i18n="flow.templates">Templates</button><button
class="secondary flow-desktop-action" type="button" data-action="import-flow"
data-i18n="flow.import">Import</button><button class="secondary flow-desktop-action" type="button"
data-action="export-flow" data-i18n="flow.export">Export</button><button class="secondary flow-desktop-action"
type="button" data-action="flow-dry-run" data-i18n="flow.dryRun">Dry-run</button><button
class="secondary flow-desktop-action" type="button" data-action="flow-logs"
data-i18n="flow.logs">Logs</button><label class="flow-enabled"><input type="checkbox" id="flowEnabled"
checked><span id="flowEnabledLabel" data-i18n="common.enabled">Enabled</span></label><span
id="flowSaveStatus" class="flow-save-status" aria-live="polite"></span><span id="flowCompileStatus"
class="badge flow-compile-status"></span><button class="secondary flow-mobile-actions-button" type="button"
data-action="flow-mobile-actions" data-i18n="flow.actions">Actions</button></div>
<button class="primary flow-save-button" type="button" data-action="save-flow"
data-i18n="actions.save">Save</button>
</header>
<div class="flow-editor-body">
<aside class="flow-palette">
<div class="flow-palette-head"><strong data-i18n="flow.blocks">Blocks</strong><small
data-i18n="flow.paletteHint">Add a block, then connect its output to the next block.</small></div>
<div class="flow-palette-group flow-palette-trigger"><span data-i18n="flow.triggers">Wyzwalacze</span>
<button type="button" data-flow-add="cron_trigger" data-i18n="flow.node.cronTrigger">CRON</button>
</div>
<div class="flow-palette-group flow-palette-time"><span data-i18n="flow.time">Czas</span>
<button type="button" data-flow-add="weekday" data-i18n="flow.node.weekday">Dni tygodnia</button><button
type="button" data-flow-add="time_range" data-i18n="flow.node.timeRange">Przedział godzin</button><button
type="button" data-flow-add="date_range" data-i18n="flow.node.dateRange">Zakres dat</button><button
type="button" data-flow-add="night_mode" data-i18n="flow.node.nightMode">Tryb nocny</button>
</div>
<div class="flow-palette-group flow-palette-timeop"><span data-i18n="flow.timeOps">Operacje czasu</span>
<button type="button" data-flow-add="stable_for" data-i18n="flow.node.stableFor">Utrzymuje się
przez…</button><button type="button" data-flow-add="state_duration" data-i18n="flow.node.stateDuration">Czas
trwania stanu</button><button type="button" data-flow-add="on_change" data-i18n="flow.node.onChange">Tylko
przy zmianie</button><button type="button" data-flow-add="rate_limit" data-i18n="flow.node.rateLimit">Maks.
X razy / okres</button><button type="button" data-flow-add="delay"
data-i18n="flow.node.delay">Odczekaj…</button>
</div>
<div class="flow-palette-group flow-palette-sensor"><span data-i18n="flow.sensors">Sensory / wartości</span>
<button type="button" data-flow-add="outdoor_temperature" data-i18n="flow.node.outdoorTemperature">Temperatura
zewn.</button><button type="button" data-flow-add="device_temperature"
data-i18n="flow.node.deviceTemperature">Temperatura urządzenia</button><button type="button"
data-flow-add="zone_temperature" data-i18n="flow.node.zoneTemperature">Temperatura strefy</button><button
type="button" data-flow-add="house_mode" data-i18n="flow.node.houseMode">Tryb domu</button><button
type="button" data-flow-add="device_state" data-i18n="flow.node.deviceState">Stan urządzenia</button><button
type="button" data-flow-add="zone_state" data-i18n="flow.node.zoneState">Stan termostatu</button><button
type="button" data-flow-add="group_state" data-i18n="flow.node.groupState">Stan grupy</button><button
type="button" data-flow-add="ha_state" data-i18n="flow.node.haState">HA: stan</button><button type="button"
data-flow-add="ha_numeric" data-i18n="flow.node.haNumeric">HA: wartość</button><button type="button"
data-flow-add="ha_attribute" data-i18n="flow.node.haAttribute">HA: atrybut</button><button type="button"
data-flow-add="ha_available" data-i18n="flow.node.haAvailable">HA: dostępność</button><button type="button"
data-flow-add="constant" data-i18n="flow.node.constant">Stała testowa</button><button type="button"
data-flow-add="shared_input" data-i18n="flow.node.sharedInput">Wspólne wejście</button><button type="button"
data-flow-add="rolling_stat" data-i18n="flow.node.rollingStat">Średnia / mediana</button><button
type="button" data-flow-add="oscillates" data-i18n="flow.node.oscillates">Wartość oscyluje</button>
</div>
<div class="flow-palette-group flow-palette-logic"><span data-i18n="flow.logic">Logika</span><button
type="button" data-flow-add="logic_and" data-i18n="flow.node.and">AND</button><button type="button"
data-flow-add="logic_or" data-i18n="flow.node.or">OR</button><button type="button" data-flow-add="logic_not"
data-i18n="flow.node.not">NOT</button></div>
<div class="flow-palette-group flow-palette-action"><span data-i18n="flow.actions">Akcje</span>
<button type="button" data-flow-add="zone_thermostat"
data-i18n="flow.node.thermostat">Termostat</button><button type="button" data-flow-add="device_action"
data-i18n="flow.node.greeDevice">Urządzenie GREE</button><button type="button" data-flow-add="group_action"
data-i18n="flow.node.group">Grupa</button>
</div>
<div class="flow-palette-group flow-palette-haaction"><span data-i18n="flow.haActions">Home Assistant</span>
<button type="button" data-flow-add="ha_service_action" data-i18n="flow.node.haServiceAction">Home Assistant:
usługa</button>
</div>
</aside>
<div class="flow-workspace-wrap">
<div class="flow-workspace-toolbar">
<div class="flow-workspace-primary-actions"><button type="button" class="primary flow-add-block-button"
data-action="flow-add-block"><span aria-hidden="true"></span><span data-i18n="flow.addBlock">Add
block</span></button><button type="button" class="secondary flow-selection-action"
data-action="flow-select-all" data-i18n="flow.selectAll">Zaznacz wszystko</button><button type="button"
class="secondary flow-selection-action" data-action="flow-clear-selection"
data-i18n="flow.clearSelection">Wyczyść zaznaczenie</button><span id="flowSelectionCount"
class="badge"></span></div>
<div class="flow-zoom-controls" role="group" data-i18n-aria="flow.zoomControls" aria-label="Canvas zoom">
<button type="button" class="secondary icon-button" data-action="flow-zoom-out"
data-i18n-title="flow.zoomOut" title="Zoom out"></button><span id="flowZoomLabel"
aria-live="polite">100%</span><button type="button" class="secondary icon-button"
data-action="flow-zoom-in" data-i18n-title="flow.zoomIn" title="Zoom in"></button><button type="button"
class="secondary flow-fit-button" data-action="flow-fit" data-i18n="flow.fitView">Fit</button></div>
</div>
<div id="flowWorkspace" class="flow-workspace" tabindex="0">
<div id="flowCanvas" class="flow-canvas"><svg id="flowEdges" class="flow-edges" aria-hidden="true"></svg>
<div id="flowNodes" class="flow-nodes"></div>
</div>
<div id="flowEmptyHint" class="flow-empty-hint"><strong data-i18n="flow.emptyCanvas">Start by adding
blocks</strong><span data-i18n="flow.emptyCanvasHint">Conditions go on the left, actions on the
right.</span><button type="button" class="primary" data-action="flow-add-block"
data-i18n="flow.addBlock">Add block</button></div>
</div>
<div class="flow-natural-preview" id="flowNaturalPreview">
<button type="button" class="flow-preview-toggle" data-action="flow-preview-toggle"
aria-expanded="false"><strong data-i18n="flow.interpretation">Interpretation</strong><span
class="flow-preview-toggle-icon" aria-hidden="true"></span></button>
<div class="flow-preview-details">
<div class="flow-preview-item flow-preview-interpretation"><strong
data-i18n="flow.interpretation">Interpretation</strong><span id="flowInterpretation"></span></div>
<div class="flow-preview-item flow-preview-runtime" id="flowRuntimeInfo"><strong
data-i18n="flow.runtimeInfo">Flow cycle</strong><span id="flowRuntimeSummary"></span></div>
</div>
</div>
</div>
<aside id="flowInspector" class="flow-inspector">
<div class="empty compact"><strong data-i18n="flow.selectBlock">Select a block</strong><span
data-i18n="flow.selectBlockHint">Its settings will appear here.</span></div>
</aside>
</div>
</section>
<dialog id="flowBlockDialog" class="sheet flow-block-dialog">
<div class="dialog-head"><div><span class="eyebrow" data-i18n="flow.blocks">Blocks</span><h2 data-i18n="flow.addBlock">Add block</h2></div><button type="button" data-close aria-label="Close">×</button></div>
<div class="flow-block-search"><input id="flowBlockSearch" type="search" autocomplete="off" data-i18n-placeholder="flow.searchBlocks" placeholder="Search blocks"></div>
<div class="dialog-head">
<div><span class="eyebrow" data-i18n="flow.blocks">Blocks</span>
<h2 data-i18n="flow.addBlock">Add block</h2>
</div><button type="button" data-close aria-label="Close">×</button>
</div>
<div class="flow-block-search"><input id="flowBlockSearch" type="search" autocomplete="off"
data-i18n-placeholder="flow.searchBlocks" placeholder="Search blocks…"></div>
<div id="flowBlockLibrary" class="flow-block-library"></div>
</dialog>
<dialog id="flowEditorActionsDialog" class="sheet flow-editor-actions-dialog">
<div class="dialog-head"><h2 data-i18n="flow.actions">Actions</h2><button type="button" data-close>×</button></div>
<div class="dialog-head">
<h2 data-i18n="flow.actions">Actions</h2><button type="button" data-close>×</button>
</div>
<div class="menu-list">
<button type="button" data-action="flow-templates"><span data-i18n="flow.templates">Templates</span><span></span></button>
<button type="button" data-action="flow-templates"><span
data-i18n="flow.templates">Templates</span><span></span></button>
<button type="button" data-action="import-flow"><span data-i18n="flow.import">Import</span><span></span></button>
<button type="button" data-action="export-flow"><span data-i18n="flow.export">Export</span><span></span></button>
<button type="button" data-action="flow-dry-run"><span data-i18n="flow.dryRun">Dry-run</span><span></span></button>
<button type="button" data-action="flow-dry-run"><span
data-i18n="flow.dryRun">Dry-run</span><span></span></button>
<button type="button" data-action="flow-logs"><span data-i18n="flow.logs">Logs</span><span></span></button>
</div>
</dialog>
@@ -770,43 +928,78 @@
<dialog id="flowSharedInputDialog">
<form id="flowSharedInputForm" class="dialog-form">
<div class="dialog-head"><div><span class="eyebrow" data-i18n="flow.sharedInputEyebrow">Wspólne dane</span><h2 id="flowSharedInputDialogTitle" data-i18n="flow.sharedInputTitle">Wspólne wejście Flow</h2></div><button type="button" data-close>×</button></div>
<div class="dialog-head">
<div><span class="eyebrow" data-i18n="flow.sharedInputEyebrow">Wspólne dane</span>
<h2 id="flowSharedInputDialogTitle" data-i18n="flow.sharedInputTitle">Wspólne wejście Flow</h2>
</div><button type="button" data-close>×</button>
</div>
<input type="hidden" name="id">
<label><span data-i18n="common.name">Nazwa</span><input name="name" maxlength="100" required placeholder="Okno w salonie zamknięte"></label>
<label><span data-i18n="flow.sharedInputType">Typ źródła</span><select name="kind" id="flowSharedInputKind"></select></label>
<label><span data-i18n="common.name">Nazwa</span><input name="name" maxlength="100" required
placeholder="Okno w salonie zamknięte"></label>
<label><span data-i18n="flow.sharedInputType">Typ źródła</span><select name="kind"
id="flowSharedInputKind"></select></label>
<div id="flowSharedInputFields" class="flow-shared-input-fields"></div>
<div id="flowSharedInputTestPanel" class="flow-shared-test-panel" hidden>
<div><strong data-i18n="flow.sharedInputTest">Testuj wejście HA</strong><p class="field-note" data-i18n="flow.sharedInputTestHint">Test używa zapisanej konfiguracji połączenia Home Assistant i nie zapisuje tego wejścia.</p></div>
<button type="button" class="secondary" id="flowSharedInputTest" data-i18n="flow.sharedInputTest">Testuj wejście HA</button>
<div id="flowSharedInputTestResult" class="flow-shared-test-result" role="status" aria-live="polite" hidden></div>
<div><strong data-i18n="flow.sharedInputTest">Testuj wejście HA</strong>
<p class="field-note" data-i18n="flow.sharedInputTestHint">Test używa zapisanej konfiguracji połączenia Home
Assistant i nie zapisuje tego wejścia.</p>
</div>
<button type="button" class="secondary" id="flowSharedInputTest" data-i18n="flow.sharedInputTest">Testuj wejście
HA</button>
<div id="flowSharedInputTestResult" class="flow-shared-test-result" role="status" aria-live="polite" hidden>
</div>
</div>
<div class="form-actions"><button type="button" class="secondary" data-close data-i18n="actions.cancel">Anuluj</button><button type="submit" class="primary" data-i18n="actions.save">Zapisz</button></div>
<div class="form-actions"><button type="button" class="secondary" data-close
data-i18n="actions.cancel">Anuluj</button><button type="submit" class="primary"
data-i18n="actions.save">Zapisz</button></div>
</form>
</dialog>
<dialog id="flowTemplateDialog" class="dialog-wide">
<div class="dialog-form">
<div class="dialog-head"><div><span class="eyebrow" data-i18n="flow.templateLibrary">Flow library</span><h2 data-i18n="flow.templates">Templates</h2></div><button type="button" data-close>×</button></div>
<p class="field-note" data-i18n="flow.templatesHint">Ready-made layouts create an editable graph using existing zones, devices and groups.</p>
<div class="flow-template-toolbar"><label><span data-i18n="flow.templateSearchLabel">Szukaj presetów</span><input id="flowTemplateSearch" type="search" autocomplete="off" data-i18n-placeholder="flow.templateSearch" placeholder="Szukaj presetów…"></label></div>
<div class="dialog-head">
<div><span class="eyebrow" data-i18n="flow.templateLibrary">Flow library</span>
<h2 data-i18n="flow.templates">Templates</h2>
</div><button type="button" data-close>×</button>
</div>
<p class="field-note" data-i18n="flow.templatesHint">Ready-made layouts create an editable graph using existing
zones, devices and groups.</p>
<div class="flow-template-toolbar"><label><span data-i18n="flow.templateSearchLabel">Szukaj presetów</span><input
id="flowTemplateSearch" type="search" autocomplete="off" data-i18n-placeholder="flow.templateSearch"
placeholder="Szukaj presetów…"></label></div>
<div class="flow-template-browser">
<div class="flow-template-catalog">
<div id="flowTemplateTabs" class="flow-template-tabs" role="tablist" data-i18n-aria="flow.templateCategories" aria-label="Preset categories"></div>
<div id="flowTemplateTabs" class="flow-template-tabs" role="tablist" data-i18n-aria="flow.templateCategories"
aria-label="Preset categories"></div>
<div id="flowTemplateList" class="flow-template-list"></div>
</div>
<aside id="flowTemplatePreview" class="flow-template-preview"><div class="empty compact"><strong data-i18n="flow.templatePreview">Podgląd presetu</strong><span data-i18n="flow.templateSelectPreview">Wybierz preset, aby zobaczyć podgląd.</span></div></aside>
<aside id="flowTemplatePreview" class="flow-template-preview">
<div class="empty compact"><strong data-i18n="flow.templatePreview">Podgląd presetu</strong><span
data-i18n="flow.templateSelectPreview">Wybierz preset, aby zobaczyć podgląd.</span></div>
</aside>
</div>
</div>
</dialog>
<dialog id="flowTestDialog" class="dialog-wide">
<div class="dialog-form">
<div class="dialog-head"><div><span class="eyebrow" data-i18n="flow.testMode">Flow diagnostics</span><h2 id="flowTestTitle" data-i18n="flow.dryRun">Dry-run</h2></div><button type="button" data-close>×</button></div>
<div class="dialog-head">
<div><span class="eyebrow" data-i18n="flow.testMode">Flow diagnostics</span>
<h2 id="flowTestTitle" data-i18n="flow.dryRun">Dry-run</h2>
</div><button type="button" data-close>×</button>
</div>
<div id="flowSimulationControls" class="flow-simulation-controls">
<p class="field-note" data-i18n="flow.dryRunHint">Dry-run does not change thermostat, device, group, schedule or automation state.</p>
<label><span data-i18n="flow.simulationTime">Simulation date and time</span><input id="flowSimulationAt" type="datetime-local"></label>
<div><strong data-i18n="flow.simulationOverrides">Sensor overrides</strong><p class="field-note" data-i18n="flow.simulationOverridesHint">Leave blank to use the current application or Home Assistant state.</p><div id="flowSimulationOverrides" class="flow-simulation-overrides"></div></div>
<div class="form-actions"><button class="primary" type="button" data-action="run-flow-dry-run" data-i18n="flow.runSimulation">Run simulation</button></div>
<p class="field-note" data-i18n="flow.dryRunHint">Dry-run does not change thermostat, device, group, schedule or
automation state.</p>
<label><span data-i18n="flow.simulationTime">Simulation date and time</span><input id="flowSimulationAt"
type="datetime-local"></label>
<div><strong data-i18n="flow.simulationOverrides">Sensor overrides</strong>
<p class="field-note" data-i18n="flow.simulationOverridesHint">Leave blank to use the current application or
Home Assistant state.</p>
<div id="flowSimulationOverrides" class="flow-simulation-overrides"></div>
</div>
<div class="form-actions"><button class="primary" type="button" data-action="run-flow-dry-run"
data-i18n="flow.runSimulation">Run simulation</button></div>
</div>
<div id="flowTestResults" class="flow-test-results"></div>
</div>
@@ -819,13 +1012,17 @@
<button class="desktop-nav-only" data-nav="groups"><span></span><b data-i18n="nav.groups">Groups</b></button>
<span class="nav-section-label desktop-nav-only" data-i18n="nav.sectionAutomation">Automatyzacja</span>
<button data-nav="flows"><span></span><b data-i18n="nav.flows">Flow</b></button>
<button class="desktop-nav-only" data-nav="schedules"><span></span><b data-i18n="nav.schedules">Schedules</b></button>
<button class="desktop-nav-only" data-nav="automations"><span></span><b data-i18n="nav.automations">Automations</b></button>
<button class="desktop-nav-only" data-nav="schedules"><span></span><b
data-i18n="nav.schedules">Schedules</b></button>
<button class="desktop-nav-only" data-nav="automations"><span></span><b
data-i18n="nav.automations">Automations</b></button>
<span class="nav-section-label desktop-nav-only" data-i18n="nav.sectionData">Dane i system</span>
<button data-nav="history"><span></span><b data-i18n="nav.history">History</b></button>
<button class="desktop-nav-only" data-nav="devices"><span></span><b data-i18n="nav.devices">Devices</b></button>
<button class="desktop-nav-only" data-nav="homeassistant"><span>HA</span><b data-i18n="nav.homeAssistantShort">Home Assistant</b></button>
<button class="desktop-nav-only" data-nav="simulation"><span></span><b data-i18n="nav.simulation">Simulator</b></button>
<button class="desktop-nav-only" data-nav="homeassistant"><span>HA</span><b data-i18n="nav.homeAssistantShort">Home
Assistant</b></button>
<button class="desktop-nav-only" data-nav="simulation"><span></span><b
data-i18n="nav.simulation">Simulator</b></button>
<button class="desktop-nav-only" data-nav="night"><span></span><b data-i18n="nav.nightMode">Night mode</b></button>
<button class="desktop-nav-only" data-nav="logs"><span></span><b data-i18n="nav.logs">Events</b></button>
<button class="desktop-nav-only" data-nav="settings"><span></span><b data-i18n="nav.settings">Settings</b></button>
@@ -923,13 +1120,16 @@
<h2 data-i18n="devices.technicalConfig">Technical configuration</h2><button type="button" data-close>×</button>
</div>
<label><span data-i18n="common.name">Name</span><input name="name" required maxlength="80"></label>
<div class="two"><label><span data-i18n="devices.ipAddress">IP address</span><input name="ip" required></label><label><span>Port</span><input type="number" name="port" min="1" max="65535" required></label></div>
<div class="two"><label><span data-i18n="devices.ipAddress">IP address</span><input name="ip"
required></label><label><span>Port</span><input type="number" name="port" min="1" max="65535"
required></label></div>
<label><span data-i18n="devices.protocol">Protocol</span><select name="protocol_version">
<option value="0" data-i18n="devices.protocolAuto">Auto (V1 + V2)</option>
<option value="1">V1 AES-ECB</option>
<option value="2">V2 AES-GCM</option>
</select></label>
<p class="field-note" data-i18n="devices.protocolChangeHint">Changing protocol clears the saved device key. Save and check connection immediately performs the required bind and test.</p>
<p class="field-note" data-i18n="devices.protocolChangeHint">Changing protocol clears the saved device key. Save
and check connection immediately performs the required bind and test.</p>
<div id="deviceConfigCheckResult" class="config-check-result" hidden></div>
<div class="form-actions technical-config-actions"><button type="button" class="secondary" data-close
data-i18n="actions.cancel">Cancel</button><button class="secondary" type="submit" data-save-mode="save"
@@ -941,14 +1141,19 @@
<dialog id="pingDialog" class="dialog-wide ping-dialog">
<div class="dialog-form">
<div class="dialog-head">
<div><span class="eyebrow" data-i18n="devices.diagnostics">Diagnostics</span><h2 data-i18n="devices.pingLive">Live ping</h2></div>
<div><span class="eyebrow" data-i18n="devices.diagnostics">Diagnostics</span>
<h2 data-i18n="devices.pingLive">Live ping</h2>
</div>
<button type="button" data-close>×</button>
</div>
<p class="field-note" data-i18n="devices.pingHint">Measures a minimal GREE round-trip without changing device state, error counters or automation ownership. The chart refreshes while monitoring is enabled.</p>
<p class="field-note" data-i18n="devices.pingHint">Measures a minimal GREE round-trip without changing device
state, error counters or automation ownership. The chart refreshes while monitoring is enabled.</p>
<div class="ping-toolbar">
<label><span data-i18n="common.device">Device</span><select id="pingDeviceSelect"></select></label>
<label class="check ping-all-toggle"><input type="checkbox" id="pingAllDevices"> <span data-i18n="devices.pingAll">Ping all units</span></label>
<button type="button" class="primary" id="pingToggleButton" data-action="ping-toggle" data-i18n="devices.pingStop">Stop</button>
<label class="check ping-all-toggle"><input type="checkbox" id="pingAllDevices"> <span
data-i18n="devices.pingAll">Ping all units</span></label>
<button type="button" class="primary" id="pingToggleButton" data-action="ping-toggle"
data-i18n="devices.pingStop">Stop</button>
</div>
<div class="ping-live-grid" id="pingLiveGrid"></div>
</div>