This commit is contained in:
Mateusz Gruszczyński
2026-09-17 08:52:02 +02:00
parent ff4f2b60e7
commit b7846c3b9f
87 changed files with 3783 additions and 1418 deletions
+280 -127
View File
@@ -31,7 +31,8 @@
</select>
</div>
<div class="toolbar-picker" data-i18n-title="controls.theme" title="Theme">
<span class="toolbar-picker-value theme-picker-value" id="themeIcon" data-ui-icon="system" aria-hidden="true"></span>
<span class="toolbar-picker-value theme-picker-value" id="themeIcon" data-ui-icon="system"
aria-hidden="true"></span>
<span class="toolbar-picker-chevron" data-ui-icon="chevron-down" aria-hidden="true"></span>
<select class="toolbar-picker-select" id="themeSelect" data-i18n-aria="controls.theme" aria-label="Theme">
<option value="system" data-i18n="theme.system">System</option>
@@ -146,7 +147,11 @@
<div><span class="eyebrow" data-i18n="devices.localCloud">Local / GREE Cloud</span>
<h1 data-i18n="nav.devices">Devices</h1>
</div>
<div class="section-heading-actions"><button class="primary compact" id="discoverButton" data-i18n="devices.discoverLocal">Discover Local</button><button class="secondary" type="button" id="cloudDiscoverButton">GREE Cloud</button><button class="secondary" type="button" id="deviceGroupsButton" data-i18n="devices.installations">Split / multisplit installations</button><button class="secondary" data-open="deviceDialog" data-i18n="devices.addLocalManual">Add Local manually</button></div>
<div class="section-heading-actions"><button class="primary compact" id="discoverButton"
data-i18n="devices.discoverLocal">Discover Local</button><button class="secondary" type="button"
id="cloudDiscoverButton">GREE Cloud</button><button class="secondary" type="button" id="deviceGroupsButton"
data-i18n="devices.installations">Split / multisplit installations</button><button class="secondary"
data-open="deviceDialog" data-i18n="devices.addLocalManual">Add Local 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>
@@ -334,12 +339,13 @@
<div class="panel chart-panel history-toolbar-panel">
<div class="chart-toolbar">
<div id="historyContextControls" class="history-context-controls"></div>
<label class="history-range-control" id="historyRangeControl"><span data-i18n="history.range">Range</span><select id="historyHours"
data-i18n-aria="history.range" aria-label="History range">
<label class="history-range-control" id="historyRangeControl"><span
data-i18n="history.range">Range</span><select id="historyHours" data-i18n-aria="history.range"
aria-label="History range">
<option value="6" data-i18n="history.6h">6 hours</option>
<option value="24" selected data-i18n="history.24h">24 hours</option>
<option value="24" data-i18n="history.24h">24 hours</option>
<option value="168" data-i18n="history.7d">7 days</option>
<option value="720" data-i18n="history.30d">30 days</option>
<option value="720" selected data-i18n="history.30d">30 days</option>
<option value="2160" data-i18n="history.90d">90 days</option>
<option value="8760" data-i18n="history.1y">1 year</option>
</select><small id="historyRangeHint" hidden></small></label>
@@ -414,19 +420,21 @@
</div>
</div>
<div class="form-grid">
<div id="haSupervisorStatus" class="ha-supervisor-status wide" role="status" aria-live="polite" hidden></div>
<div id="haSupervisorStatus" class="ha-supervisor-status wide" role="status" aria-live="polite" hidden>
</div>
<label class="wide" data-ha-manual-field><span>URL</span><input type="url" name="ha_url"
placeholder="http://homeassistant.local:8123"></label>
<label class="wide" data-ha-manual-field><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="wide" data-ha-manual-field><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" data-ha-manual-field><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-ha-manual-field data-i18n="settings.allowInvalidTlsHint">Use only for a trusted
<p class="field-note wide warning-note" data-ha-manual-field 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="haUseSupervisor"
data-i18n="settings.haUseSupervisor" hidden>Use Supervisor automatically</button><button type="button" class="secondary" id="haTest"
data-i18n="settings.testHa">Test HA</button></div>
data-i18n="settings.haUseSupervisor" hidden>Use Supervisor automatically</button><button type="button"
class="secondary" id="haTest" data-i18n="settings.testHa">Test HA</button></div>
</div>
</section>
@@ -439,9 +447,11 @@
</div>
</div>
<div class="form-grid">
<label class="wide"><span data-i18n="settings.outdoorEntity">Global outdoor temperature entity_id</span><input
name="ha_outdoor_entity_id" list="haEntitySuggestions" placeholder="sensor.outdoor_temperature"></label>
<p class="field-note wide" data-i18n="settings.outdoorEntityHint">Global Home Assistant outdoor temperature sensor. Zones use it by default and may override it with another outdoor sensor in zone settings.</p>
<label class="wide"><span data-i18n="settings.outdoorEntity">Global outdoor temperature
entity_id</span><input name="ha_outdoor_entity_id" list="haEntitySuggestions"
placeholder="sensor.outdoor_temperature"></label>
<p class="field-note wide" data-i18n="settings.outdoorEntityHint">Global Home Assistant outdoor temperature
sensor. Zones use it by default and may override it with another outdoor sensor in zone settings.</p>
<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>
@@ -475,9 +485,10 @@
</div>
<div class="sensor-alias-manager">
<div id="sensorAliasList" class="sensor-alias-list"></div>
<div class="sensor-alias-add"><input id="sensorAliasEntity" list="haEntitySuggestions" 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" list="haEntitySuggestions"
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>
@@ -587,7 +598,8 @@
<label class="check"><input type="checkbox" name="notification_alert_automation"> <span
data-i18n="notifications.alertAutomation">Automation errors and conflicts</span></label>
<label class="check"><input type="checkbox" name="notification_alert_sensor_discrepancy"> <span
data-i18n="notifications.alertSensorDiscrepancy">GREE vs Home Assistant temperature difference</span></label>
data-i18n="notifications.alertSensorDiscrepancy">GREE vs Home Assistant temperature
difference</span></label>
<label class="check"><input type="checkbox" name="notification_alert_control_errors"> <span
data-i18n="notifications.alertControlErrors">Thermostat and group control errors</span></label>
<label class="check"><input type="checkbox" name="notification_alert_important_events"> <span
@@ -652,6 +664,9 @@
autocomplete="new-password" data-i18n-placeholder="settings.secretKeep"
placeholder="Leave empty to keep saved secret"></label>
</div>
<div class="form-actions wide"><button type="button" class="secondary" id="testInfluxDbConnection"
data-i18n="settings.influxTest">Test InfluxDB connection</button></div>
<div id="influxDbTestResult" class="inline-alert wide" role="status" aria-live="polite" hidden></div>
</div>
</section>
<section class="panel form-section">
@@ -714,14 +729,19 @@
<div class="form-section-head">
<div>
<h3 data-i18n="settings.connectivityTitle">Connectivity metrics</h3>
<p data-i18n="settings.connectivityHint">Periodic GREE UDP round-trip measurements for Local/LAN units. Results are stored in History.</p>
<p data-i18n="settings.connectivityHint">Periodic GREE UDP round-trip measurements for Local/LAN units.
Results are stored in History.</p>
</div>
</div>
<div class="form-grid">
<label class="check wide"><input type="checkbox" name="ping_metrics_enabled"> <span data-i18n="settings.connectivityEnable">Enable local unit ping measurements</span></label>
<label><span data-i18n="settings.connectivityInterval">Measurement interval (s)</span><input type="number" name="ping_interval_seconds" min="10" max="3600" value="60"></label>
<label><span data-i18n="settings.connectivitySamples">Samples per measurement</span><input type="number" name="ping_sample_count" min="1" max="10" value="3"></label>
<p class="field-note wide" data-i18n="settings.connectivityLocalOnly">Only Local/LAN installations are probed. Cloud devices are not pinged directly.</p>
<label class="check wide"><input type="checkbox" name="ping_metrics_enabled"> <span
data-i18n="settings.connectivityEnable">Enable local unit ping measurements</span></label>
<label><span data-i18n="settings.connectivityInterval">Measurement interval (s)</span><input type="number"
name="ping_interval_seconds" min="10" max="3600" value="60"></label>
<label><span data-i18n="settings.connectivitySamples">Samples per measurement</span><input type="number"
name="ping_sample_count" min="1" max="10" value="3"></label>
<p class="field-note wide" data-i18n="settings.connectivityLocalOnly">Only Local/LAN installations are
probed. Cloud devices are not pinged directly.</p>
</div>
</section>
<section class="panel form-section">
@@ -757,33 +777,70 @@
</div>
<div class="settings-pane" data-settings-pane="cloud" hidden>
<section class="panel form-section">
<div class="form-section-head"><div><h3 data-i18n="settings.cloudAccountTitle">GREE Cloud account</h3><p data-i18n="settings.cloudAccountHint">REST login and device discovery use the selected regional GREE service. The password is never returned by the API after it is saved.</p></div></div>
<div class="form-section-head">
<div>
<h3 data-i18n="settings.cloudAccountTitle">GREE Cloud account</h3>
<p data-i18n="settings.cloudAccountHint">REST login and device discovery use the selected regional GREE
service. The password is never returned by the API after it is saved.</p>
</div>
</div>
<div class="form-grid">
<label class="check wide"><input type="checkbox" name="gree_cloud_enabled"> <span data-i18n="settings.cloudEnable">Enable GREE Cloud</span></label>
<label class="check wide"><input type="checkbox" name="gree_cloud_enabled"> <span
data-i18n="settings.cloudEnable">Enable GREE Cloud</span></label>
<label><span data-i18n="settings.cloudRegion">Region</span><select name="gree_cloud_region">
<option>Australia</option><option>China Mainland</option><option>East South Asia</option><option selected>Europe</option><option>India</option><option>Latin American</option><option>Middle East</option><option>North American</option><option>Russia</option><option>South American</option>
</select></label>
<label><span data-i18n="settings.cloudPolling">Cloud fallback polling interval (s)</span><input type="number" name="gree_cloud_polling_interval_seconds" min="30" max="3600" value="60"></label>
<label class="wide"><span data-i18n="settings.cloudLogin">Login / email</span><input name="gree_cloud_username" autocomplete="username"></label>
<label class="wide"><span data-i18n="settings.cloudPassword">Password</span><input type="password" name="gree_cloud_password" autocomplete="new-password" data-i18n-placeholder="settings.cloudPasswordPlaceholder" placeholder="Leave empty to keep saved secret"></label>
<option>Australia</option>
<option>China Mainland</option>
<option>East South Asia</option>
<option selected>Europe</option>
<option>India</option>
<option>Latin American</option>
<option>Middle East</option>
<option>North American</option>
<option>Russia</option>
<option>South American</option>
</select></label>
<label><span data-i18n="settings.cloudPolling">Cloud fallback polling interval (s)</span><input
type="number" name="gree_cloud_polling_interval_seconds" min="30" max="3600" value="60"></label>
<label class="wide"><span data-i18n="settings.cloudLogin">Login / email</span><input
name="gree_cloud_username" autocomplete="username"></label>
<label class="wide"><span data-i18n="settings.cloudPassword">Password</span><input type="password"
name="gree_cloud_password" autocomplete="new-password"
data-i18n-placeholder="settings.cloudPasswordPlaceholder"
placeholder="Leave empty to keep saved secret"></label>
<div class="wide cloud-runtime-summary" aria-live="polite" hidden>
<div><span data-i18n="settings.cloudAccountStatus">Account status</span><strong id="greeCloudAccountStatus"></strong></div>
<div><span data-i18n="settings.cloudMqttStatus">MQTT status</span><strong id="greeCloudMqttStatus"></strong></div>
<div><span data-i18n="settings.cloudDevicesOnline">Devices online</span><strong id="greeCloudDevicesOnline"></strong></div>
<div><span data-i18n="settings.cloudRestResponseTime">Last REST response time</span><strong id="greeCloudRestResponseTime"></strong></div>
<div><span data-i18n="settings.cloudResponseTime">Last device response time</span><strong id="greeCloudResponseTime"></strong></div>
<div><span data-i18n="settings.cloudLastDeviceResponse">Last device response</span><strong id="greeCloudLastDeviceResponse"></strong></div>
<div><span data-i18n="settings.cloudLastMqttMessage">Last MQTT activity</span><strong id="greeCloudLastMqttMessage"></strong></div>
<div><span data-i18n="settings.cloudConnectedSince">MQTT connected since</span><strong id="greeCloudConnectedSince"></strong></div>
<div><span data-i18n="settings.cloudAccountStatus">Account status</span><strong
id="greeCloudAccountStatus"></strong></div>
<div><span data-i18n="settings.cloudMqttStatus">MQTT status</span><strong
id="greeCloudMqttStatus"></strong></div>
<div><span data-i18n="settings.cloudDevicesOnline">Devices online</span><strong
id="greeCloudDevicesOnline"></strong></div>
<div><span data-i18n="settings.cloudRestResponseTime">REST response time</span><strong
id="greeCloudRestResponseTime"></strong></div>
<div><span data-i18n="settings.cloudResponseTime">Device response time</span><strong
id="greeCloudResponseTime"></strong></div>
<div><span data-i18n="settings.cloudLastDeviceResponse">Last device response</span><strong
id="greeCloudLastDeviceResponse"></strong></div>
<div><span data-i18n="settings.cloudLastMqttMessage">Last MQTT activity</span><strong
id="greeCloudLastMqttMessage"></strong></div>
<div><span data-i18n="settings.cloudConnectedSince">MQTT connected since</span><strong
id="greeCloudConnectedSince"></strong></div>
<div><span data-i18n="settings.cloudBroker">Broker</span><strong id="greeCloudBroker"></strong></div>
<div><span data-i18n="settings.cloudTraffic">Requests / responses / timeouts</span><strong id="greeCloudTraffic"></strong></div>
<div><span data-i18n="settings.cloudTraffic">Requests / responses / timeouts</span><strong
id="greeCloudTraffic"></strong></div>
</div>
<div class="wide cloud-account-meta">
<small hidden><span data-i18n="settings.cloudLastContact">Last successful REST contact</span>: <strong id="greeCloudLastContact"></strong></small>
<small><span data-i18n="settings.cloudInstallationId">Installation ID</span>: <code id="greeCloudInstanceId"></code></small>
<small hidden><span data-i18n="settings.cloudLastContact">Last successful REST contact</span>: <strong
id="greeCloudLastContact"></strong></small>
<small><span data-i18n="settings.cloudInstallationId">Installation ID</span>: <code
id="greeCloudInstanceId"></code></small>
</div>
<p class="field-note wide" data-i18n="settings.cloudPushHint">MQTT push is primary. Polling is used only for initial state, recovery and periodic verification.</p>
<div class="form-actions wide"><button type="button" class="secondary" id="greeCloudTestButton" data-i18n="settings.cloudTest">Test connection</button><button type="button" class="secondary" id="greeCloudRefreshButton" data-i18n="settings.cloudRefreshDevices">Refresh devices</button><button type="button" class="secondary" id="greeCloudReconnectButton" data-i18n="settings.cloudReconnect">Reconnect</button></div>
<p class="field-note wide" data-i18n="settings.cloudPushHint">MQTT push is primary. Polling is used only
for initial state, recovery and periodic verification.</p>
<div class="form-actions wide"><button type="button" class="secondary" id="greeCloudTestButton"
data-i18n="settings.cloudTest">Test connection</button><button type="button" class="secondary"
id="greeCloudRefreshButton" data-i18n="settings.cloudRefreshDevices">Refresh devices</button><button
type="button" class="secondary" id="greeCloudReconnectButton"
data-i18n="settings.cloudReconnect">Reconnect</button></div>
<div id="greeCloudTestResult" class="inline-alert wide" hidden></div>
</div>
</section>
@@ -791,14 +848,19 @@
<div class="form-section-head">
<div>
<h3 data-i18n="settings.cloudConnectivityTitle">Cloud connectivity metrics</h3>
<p data-i18n="settings.cloudConnectivityHint">Optional. Disabled by default. Measures REST login response and MQTT PINGRESP round-trip.</p>
<p data-i18n="settings.cloudConnectivityHint">Optional. Disabled by default. Measures REST login
response and MQTT PINGRESP round-trip.</p>
</div>
</div>
<div class="form-grid">
<label class="check wide"><input type="checkbox" name="gree_cloud_connectivity_metrics_enabled"> <span data-i18n="settings.cloudConnectivityEnable">Measure Cloud REST/MQTT connectivity</span></label>
<label><span data-i18n="settings.connectivityInterval">Measurement interval (s)</span><input type="number" name="gree_cloud_connectivity_metrics_interval_seconds" min="30" max="3600" value="300"></label>
<label><span data-i18n="settings.connectivitySamples">Samples per measurement</span><input type="number" name="gree_cloud_connectivity_metrics_sample_count" min="1" max="10" value="3"></label>
<p class="field-note wide" data-i18n="settings.cloudConnectivityHistoryHint">REST and MQTT measurements are stored in History → Pings together with Local/LAN measurements.</p>
<label class="check wide"><input type="checkbox" name="gree_cloud_connectivity_metrics_enabled"> <span
data-i18n="settings.cloudConnectivityEnable">Measure Cloud REST/MQTT connectivity</span></label>
<label><span data-i18n="settings.connectivityInterval">Measurement interval (s)</span><input type="number"
name="gree_cloud_connectivity_metrics_interval_seconds" min="30" max="3600" value="300"></label>
<label><span data-i18n="settings.connectivitySamples">Samples per measurement</span><input type="number"
name="gree_cloud_connectivity_metrics_sample_count" min="1" max="10" value="3"></label>
<p class="field-note wide" data-i18n="settings.cloudConnectivityHistoryHint">REST and MQTT measurements
are stored in History → Pings together with Local/LAN measurements.</p>
</div>
</section>
</div>
@@ -853,9 +915,9 @@
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" data-ui-icon="edit"></button></div><input id="flowName" maxlength="100"
data-i18n-placeholder="flow.namePlaceholder" data-i18n-title="flow.nameAliasHint"
placeholder="My automation">
title="Edit Flow name" aria-label="Edit Flow name" data-ui-icon="edit"></button></div><input
id="flowName" maxlength="100" data-i18n-placeholder="flow.namePlaceholder"
data-i18n-title="flow.nameAliasHint" placeholder="My automation">
</div>
</div>
</div>
@@ -931,7 +993,8 @@
<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 data-ui-icon="plus" aria-hidden="true"></span><span data-i18n="flow.addBlock">Add
data-action="flow-add-block"><span data-ui-icon="plus" 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"
@@ -941,10 +1004,11 @@
<button type="button" class="secondary icon-button" data-action="flow-zoom-out"
data-i18n-title="flow.zoomOut" title="Zoom out" data-ui-icon="minus"></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" data-ui-icon="plus"></button><button type="button"
class="secondary flow-fit-button" data-action="flow-fit" data-i18n-title="flow.fitView" title="Fit"><span
class="flow-fit-button-icon" data-ui-icon="fit" aria-hidden="true"></span><span
class="flow-fit-button-label" data-i18n="flow.fitView">Fit</span></button>
data-action="flow-zoom-in" data-i18n-title="flow.zoomIn" title="Zoom in"
data-ui-icon="plus"></button><button type="button" class="secondary flow-fit-button"
data-action="flow-fit" data-i18n-title="flow.fitView" title="Fit"><span class="flow-fit-button-icon"
data-ui-icon="fit" aria-hidden="true"></span><span class="flow-fit-button-label"
data-i18n="flow.fitView">Fit</span></button>
</div>
</div>
<div id="flowWorkspace" class="flow-workspace" tabindex="0">
@@ -991,13 +1055,16 @@
<h2 data-i18n="flow.actions">Actions</h2><button type="button" data-close data-ui-icon="close"></button>
</div>
<div class="menu-list">
<button type="button" data-action="flow-templates"><span
data-i18n="flow.templates">Templates</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button type="button" data-action="import-flow"><span data-i18n="flow.import">Import</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button type="button" data-action="export-flow"><span data-i18n="flow.export">Export</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button type="button" data-action="flow-dry-run"><span
data-i18n="flow.dryRun">Dry-run</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button type="button" data-action="flow-logs"><span data-i18n="flow.logs">Logs</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button type="button" data-action="flow-templates"><span data-i18n="flow.templates">Templates</span><span
data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button type="button" data-action="import-flow"><span data-i18n="flow.import">Import</span><span
data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button type="button" data-action="export-flow"><span data-i18n="flow.export">Export</span><span
data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button type="button" data-action="flow-dry-run"><span data-i18n="flow.dryRun">Dry-run</span><span
data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button type="button" data-action="flow-logs"><span data-i18n="flow.logs">Logs</span><span
data-ui-icon="chevron-right" aria-hidden="true"></span></button>
</div>
</dialog>
@@ -1084,26 +1151,36 @@
<nav class="bottom-nav" data-i18n-aria="nav.navigation" aria-label="Navigation">
<span class="nav-section-label desktop-nav-only" data-i18n="nav.sectionControl">Sterowanie</span>
<button class="active" data-nav="dashboard"><span data-ui-icon="home" aria-hidden="true"></span><b data-i18n="nav.dashboard">Dashboard</b></button>
<button data-nav="zones"><span data-ui-icon="zones" aria-hidden="true"></span><b data-i18n="nav.zones">Zones</b></button>
<button class="desktop-nav-only" data-nav="groups"><span data-ui-icon="groups" aria-hidden="true"></span><b data-i18n="nav.groups">Groups</b></button>
<button class="active" data-nav="dashboard"><span data-ui-icon="home" aria-hidden="true"></span><b
data-i18n="nav.dashboard">Dashboard</b></button>
<button data-nav="zones"><span data-ui-icon="zones" aria-hidden="true"></span><b
data-i18n="nav.zones">Zones</b></button>
<button class="desktop-nav-only" data-nav="groups"><span data-ui-icon="groups" aria-hidden="true"></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 data-ui-icon="flow" aria-hidden="true"></span><b data-i18n="nav.flows">Flow</b></button>
<button data-nav="flows"><span data-ui-icon="flow" aria-hidden="true"></span><b
data-i18n="nav.flows">Flow</b></button>
<button class="desktop-nav-only" data-nav="schedules"><span data-ui-icon="schedule" aria-hidden="true"></span><b
data-i18n="nav.schedules">Schedules</b></button>
<button class="desktop-nav-only" data-nav="automations"><span data-ui-icon="automation" aria-hidden="true"></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 data-ui-icon="history" aria-hidden="true"></span><b data-i18n="nav.history">History</b></button>
<button class="desktop-nav-only" data-nav="devices"><span data-ui-icon="devices" aria-hidden="true"></span><b data-i18n="nav.devices">Devices</b></button>
<button data-nav="history"><span data-ui-icon="history" aria-hidden="true"></span><b
data-i18n="nav.history">History</b></button>
<button class="desktop-nav-only" data-nav="devices"><span data-ui-icon="devices" aria-hidden="true"></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 data-ui-icon="play" aria-hidden="true"></span><b
data-i18n="nav.simulation">Simulator</b></button>
<button class="desktop-nav-only" data-nav="night"><span data-ui-icon="moon" aria-hidden="true"></span><b data-i18n="nav.nightMode">Night mode</b></button>
<button class="desktop-nav-only" data-nav="logs"><span data-ui-icon="events" aria-hidden="true"></span><b data-i18n="nav.logs">Events</b></button>
<button class="desktop-nav-only" data-nav="settings"><span data-ui-icon="settings" aria-hidden="true"></span><b data-i18n="nav.settings">Settings</b></button>
<button class="mobile-nav-only" data-nav="more"><span data-ui-icon="more-horizontal" aria-hidden="true"></span><b data-i18n="nav.more">More</b></button>
<button class="desktop-nav-only" data-nav="night"><span data-ui-icon="moon" aria-hidden="true"></span><b
data-i18n="nav.nightMode">Night mode</b></button>
<button class="desktop-nav-only" data-nav="logs"><span data-ui-icon="events" aria-hidden="true"></span><b
data-i18n="nav.logs">Events</b></button>
<button class="desktop-nav-only" data-nav="settings"><span data-ui-icon="settings" aria-hidden="true"></span><b
data-i18n="nav.settings">Settings</b></button>
<button class="mobile-nav-only" data-nav="more"><span data-ui-icon="more-horizontal" aria-hidden="true"></span><b
data-i18n="nav.more">More</b></button>
</nav>
<dialog id="moreDialog" class="sheet">
@@ -1112,18 +1189,26 @@
</div>
<div class="menu-list more-menu-list">
<span class="menu-section-label" data-i18n="nav.sectionControl">Sterowanie</span>
<button data-go="devices"><span data-i18n="nav.devices">Devices</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button data-go="groups"><span data-i18n="nav.groups">Groups</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button data-go="devices"><span data-i18n="nav.devices">Devices</span><span data-ui-icon="chevron-right"
aria-hidden="true"></span></button>
<button data-go="groups"><span data-i18n="nav.groups">Groups</span><span data-ui-icon="chevron-right"
aria-hidden="true"></span></button>
<span class="menu-section-label" data-i18n="nav.sectionAutomation">Automatyzacja</span>
<button data-go="schedules"><span data-i18n="nav.schedules">Schedules</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button data-go="automations"><span data-i18n="nav.automations">Automations</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button data-go="schedules"><span data-i18n="nav.schedules">Schedules</span><span data-ui-icon="chevron-right"
aria-hidden="true"></span></button>
<button data-go="automations"><span data-i18n="nav.automations">Automations</span><span
data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<span class="menu-section-label" data-i18n="nav.sectionData">Dane i system</span>
<button data-go="simulation"><span data-i18n="nav.simulation">Simulator</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button data-go="night"><span data-i18n="nav.nightMode">Night mode</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button data-go="simulation"><span data-i18n="nav.simulation">Simulator</span><span data-ui-icon="chevron-right"
aria-hidden="true"></span></button>
<button data-go="night"><span data-i18n="nav.nightMode">Night mode</span><span data-ui-icon="chevron-right"
aria-hidden="true"></span></button>
<button data-go="homeassistant"><span data-i18n="nav.homeAssistant">Home Assistant /
Sensors</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button data-go="settings"><span data-i18n="nav.settings">Settings</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button data-go="logs"><span data-i18n="nav.logsAndEvents">Events and logs</span><span data-ui-icon="chevron-right" aria-hidden="true"></span></button>
<button data-go="settings"><span data-i18n="nav.settings">Settings</span><span data-ui-icon="chevron-right"
aria-hidden="true"></span></button>
<button data-go="logs"><span data-i18n="nav.logsAndEvents">Events and logs</span><span
data-ui-icon="chevron-right" aria-hidden="true"></span></button>
</div>
</dialog>
@@ -1157,17 +1242,25 @@
<dialog id="cloudDiscoveryDialog" class="dialog-wide">
<div class="dialog-form">
<div class="dialog-head"><div><span class="eyebrow">GREE Cloud</span><h2 data-i18n="devices.cloudDiscoveryTitle">Devices on account</h2></div><button type="button" data-close data-ui-icon="close"></button></div>
<p class="field-note" data-i18n="devices.cloudDiscoveryHint">Devices are loaded from the saved GREE Cloud account. Nothing is added automatically; choose the units you want to register.</p>
<div class="dialog-head">
<div><span class="eyebrow">GREE Cloud</span>
<h2 data-i18n="devices.cloudDiscoveryTitle">Devices on account</h2>
</div><button type="button" data-close data-ui-icon="close"></button>
</div>
<p class="field-note" data-i18n="devices.cloudDiscoveryHint">Devices are loaded from the saved GREE Cloud account.
Nothing is added automatically; choose the units you want to register.</p>
<div id="cloudDiscoveryList" class="discovery-name-list"></div>
<div class="form-actions"><button type="button" class="secondary" id="cloudDiscoveryRefresh" data-i18n="actions.refresh">Refresh</button><button type="button" class="primary" data-close data-i18n="actions.done">Done</button></div>
<div class="form-actions"><button type="button" class="secondary" id="cloudDiscoveryRefresh"
data-i18n="actions.refresh">Refresh</button><button type="button" class="primary" data-close
data-i18n="actions.done">Done</button></div>
</div>
</dialog>
<dialog id="discoverDialog">
<form method="dialog" id="discoverForm" class="dialog-form">
<div class="dialog-head">
<h2 data-i18n="discovery.title">Discover GREE devices</h2><button type="button" data-close data-ui-icon="close"></button>
<h2 data-i18n="discovery.title">Discover GREE devices</h2><button type="button" data-close
data-ui-icon="close"></button>
</div>
<p class="field-note" data-i18n="discovery.help">Auto searches both AES-ECB and AES-GCM devices. Multiple passes
improve discovery when several Wi-Fi modules answer the same broadcast.</p>
@@ -1188,7 +1281,8 @@
<dialog id="discoveryNamesDialog">
<form method="dialog" id="discoveryNamesForm" class="dialog-form">
<div class="dialog-head">
<h2 data-i18n="discovery.nameDevices">Name discovered devices</h2><button type="button" data-close data-ui-icon="close"></button>
<h2 data-i18n="discovery.nameDevices">Name discovered devices</h2><button type="button" data-close
data-ui-icon="close"></button>
</div>
<p class="field-note" data-i18n="discovery.nameDevicesHelp">Give each new unit a friendly room name. The technical
model and MAC remain available in diagnostics.</p>
@@ -1203,7 +1297,8 @@
<form method="dialog" id="renameDeviceForm" class="dialog-form">
<input type="hidden" name="id">
<div class="dialog-head">
<h2 data-i18n="devices.technicalConfig">Technical configuration</h2><button type="button" data-close data-ui-icon="close"></button>
<h2 data-i18n="devices.technicalConfig">Technical configuration</h2><button type="button" data-close
data-ui-icon="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"
@@ -1228,56 +1323,101 @@
<form method="dialog" id="deviceDetailsForm" class="dialog-form">
<input type="hidden" name="id">
<div class="dialog-head">
<div><span class="eyebrow" data-i18n="devices.cloudDetails">Cloud details</span><h2 id="deviceDetailsTitle">Device details</h2></div>
<div><span class="eyebrow" data-i18n="devices.cloudDetails">Cloud details</span>
<h2 id="deviceDetailsTitle">Device details</h2>
</div>
<button type="button" data-close data-ui-icon="close"></button>
</div>
<label><span data-i18n="common.name">Name</span><input name="name" required maxlength="80"></label>
<div class="technical-device-grid" id="deviceDetailsMeta"></div>
<section class="form-section">
<div class="form-section-head"><div><h3 data-i18n="energy.title">Energy</h3><p data-i18n="energy.sourceHint">Choose the cumulative energy source used for charts and period totals.</p></div></div>
<div class="form-section-head">
<div>
<h3 data-i18n="energy.title">Energy</h3>
<p data-i18n="energy.sourceHint">Choose the cumulative energy source used for charts and period totals.</p>
</div>
</div>
<div class="form-grid">
<label><span data-i18n="energy.source">Energy source</span><select name="energy_source">
<option value="auto" data-i18n="energy.auto">Auto</option>
<option value="gree_cloud">GREE Cloud</option>
<option value="home_assistant">Home Assistant</option>
</select></label>
<label class="wide"><span data-i18n="energy.haSensor">Home Assistant energy sensor</span><select name="ha_energy_entity_id"><option value=""></option></select></label>
<option value="auto" data-i18n="energy.auto">Auto</option>
<option value="gree_cloud">GREE Cloud</option>
<option value="home_assistant">Home Assistant</option>
</select></label>
<label class="wide"><span data-i18n="energy.haSensor">Home Assistant energy sensor</span><select
name="ha_energy_entity_id">
<option value=""></option>
</select></label>
<p class="field-note wide" id="deviceEnergySensorMeta"></p>
<div class="inline-alert info wide" id="deviceEnergyGroupNote" hidden></div>
</div>
</section>
<div class="form-actions"><button type="button" class="secondary" data-close data-i18n="actions.cancel">Cancel</button><button class="primary" type="submit" data-i18n="actions.save">Save</button></div>
<div class="form-actions"><button type="button" class="secondary" data-close
data-i18n="actions.cancel">Cancel</button><button class="primary" type="submit"
data-i18n="actions.save">Save</button></div>
</form>
</dialog>
<dialog id="deviceGroupsDialog" class="dialog-wide">
<div class="dialog-form">
<div class="dialog-head"><div><span class="eyebrow" data-i18n="devices.installation">Installation</span><h2 data-i18n="devices.installations">Split / multisplit installations</h2></div><button type="button" data-close data-ui-icon="close"></button></div>
<p class="field-note" data-i18n="devices.installationsHint">Group indoor units that share one outdoor unit. Energy and outdoor temperature can use one shared source.</p>
<div class="dialog-head">
<div><span class="eyebrow" data-i18n="devices.installation">Installation</span>
<h2 data-i18n="devices.installations">Split / multisplit installations</h2>
</div><button type="button" data-close data-ui-icon="close"></button>
</div>
<p class="field-note" data-i18n="devices.installationsHint">Group indoor units that share one outdoor unit. Energy
and outdoor temperature can use one shared source.</p>
<div id="deviceGroupsList" class="installation-list"></div>
<form id="deviceGroupForm" class="installation-form">
<input type="hidden" name="id">
<div class="form-grid">
<label><span data-i18n="devices.installationName">Installation name</span><input name="name" maxlength="80" required></label>
<label><span data-i18n="devices.installationType">Installation type</span><select name="kind"><option value="split" data-i18n="devices.split">Split</option><option value="multisplit" data-i18n="devices.multisplit">Multisplit</option></select></label>
<div class="wide"><span class="field-label" data-i18n="devices.installationDevices">Indoor units</span><div id="deviceGroupDeviceChoices" class="installation-device-choices"></div></div>
<label><span data-i18n="energy.source">Energy source</span><select name="energy_source"><option value="auto" data-i18n="energy.auto">Auto</option><option value="gree_cloud">GREE Cloud</option><option value="home_assistant">Home Assistant</option></select></label>
<label><span data-i18n="devices.energySourceDevice">GREE Cloud energy source</span><select name="energy_device_id"><option value=""></option></select></label>
<label class="wide"><span data-i18n="energy.haSensor">Home Assistant energy sensor</span><select name="ha_energy_entity_id"><option value=""></option></select></label>
<label class="wide"><span data-i18n="devices.outdoorSourceDevice">Outdoor temperature source</span><select name="outdoor_temperature_device_id"><option value="" data-i18n="devices.noSharedOutdoor">No shared source</option></select></label>
<label><span data-i18n="devices.installationName">Installation name</span><input name="name" maxlength="80"
required></label>
<label><span data-i18n="devices.installationType">Installation type</span><select name="kind">
<option value="split" data-i18n="devices.split">Split</option>
<option value="multisplit" data-i18n="devices.multisplit">Multisplit</option>
</select></label>
<div class="wide"><span class="field-label" data-i18n="devices.installationDevices">Indoor units</span>
<div id="deviceGroupDeviceChoices" class="installation-device-choices"></div>
</div>
<label><span data-i18n="energy.source">Energy source</span><select name="energy_source">
<option value="auto" data-i18n="energy.auto">Auto</option>
<option value="gree_cloud">GREE Cloud</option>
<option value="home_assistant">Home Assistant</option>
</select></label>
<label><span data-i18n="devices.energySourceDevice">GREE Cloud energy source</span><select
name="energy_device_id">
<option value=""></option>
</select></label>
<label class="wide"><span data-i18n="energy.haSensor">Home Assistant energy sensor</span><select
name="ha_energy_entity_id">
<option value=""></option>
</select></label>
<label class="wide"><span data-i18n="devices.outdoorSourceDevice">Outdoor temperature source</span><select
name="outdoor_temperature_device_id">
<option value="" data-i18n="devices.noSharedOutdoor">No shared source</option>
</select></label>
<p class="field-note wide" id="deviceGroupEnergySensorMeta"></p>
</div>
<div class="form-actions"><button type="button" class="secondary" id="deviceGroupNew" data-i18n="devices.newInstallation">New installation</button><button type="submit" class="primary" data-i18n="actions.save">Save</button></div>
<div class="form-actions"><button type="button" class="secondary" id="deviceGroupNew"
data-i18n="devices.newInstallation">New installation</button><button type="submit" class="primary"
data-i18n="actions.save">Save</button></div>
</form>
</div>
</dialog>
<dialog id="cloudDiagnosticsDialog" class="dialog-wide">
<div class="dialog-form">
<div class="dialog-head"><div><span class="eyebrow">GREE Cloud</span><h2 data-i18n="devices.cloudDiagnostics">Cloud diagnostics</h2></div><button type="button" data-close data-ui-icon="close"></button></div>
<p class="field-note" data-i18n="devices.cloudDiagnosticsHint">Decrypted and sanitized protocol data. Passwords, tokens and cipher keys are never included.</p>
<div class="dialog-head">
<div><span class="eyebrow">GREE Cloud</span>
<h2 data-i18n="devices.cloudDiagnostics">Cloud diagnostics</h2>
</div><button type="button" data-close data-ui-icon="close"></button>
</div>
<p class="field-note" data-i18n="devices.cloudDiagnosticsHint">Decrypted and sanitized protocol data. Passwords,
tokens and cipher keys are never included.</p>
<pre id="cloudDiagnosticsPayload" class="mono cloud-diagnostics-payload"></pre>
<div class="form-actions"><button type="button" class="secondary" id="cloudDiagnosticsRefresh" data-i18n="actions.refresh">Refresh</button><button type="button" class="primary" data-close data-i18n="actions.done">Done</button></div>
<div class="form-actions"><button type="button" class="secondary" id="cloudDiagnosticsRefresh"
data-i18n="actions.refresh">Refresh</button><button type="button" class="primary" data-close
data-i18n="actions.done">Done</button></div>
</div>
</dialog>
@@ -1359,17 +1499,20 @@
°C</span><input type="text" inputmode="decimal" step="0.1" min="0.1" max="5" name="heat_hysteresis"
value="0.6"></label></div>
<div id="externalSensorFields">
<label><span data-i18n="zones.roomSensorEntity">Room sensor entity_id</span><input name="ha_entity_id" list="haEntitySuggestions"
placeholder="sensor.living_room_temperature"></label>
<label><span data-i18n="zones.roomSensorEntity">Room sensor entity_id</span><input name="ha_entity_id"
list="haEntitySuggestions" placeholder="sensor.living_room_temperature"></label>
<div class="two"><label><span data-i18n="zones.roomSensorWeight">Room sensor weight %</span><input type="number"
step="5" min="0" max="100" name="external_sensor_weight_percent" value="40"></label><label><span
data-i18n="zones.maxDifference">Max. sensor difference °C</span><input type="text" inputmode="decimal"
step="0.1" min="0.1" max="20" name="max_sensor_difference" value="3.0"></label></div>
<p class="field-note" data-i18n="zones.sensorHelp">This room sensor is required when the temperature strategy uses Home Assistant. If it becomes unavailable, the controller falls back to the GREE sensor.</p>
<p class="field-note" data-i18n="zones.sensorHelp">This room sensor is required when the temperature strategy
uses Home Assistant. If it becomes unavailable, the controller falls back to the GREE sensor.</p>
</div>
<label><span data-i18n="zones.outdoorSensorEntity">Outdoor temperature entity_id override</span><input name="ha_outdoor_entity_id" list="haEntitySuggestions"
placeholder="sensor.outdoor_temperature"></label>
<p class="field-note" data-i18n="zones.outdoorSensorHelp">Leave empty to use the global Outdoor temperature entity_id. Set another entity_id to use a different outdoor sensor only for this zone. It is used by outdoor-temperature assist and recorded in history/metrics.</p>
<label><span data-i18n="zones.outdoorSensorEntity">Outdoor temperature entity_id override</span><input
name="ha_outdoor_entity_id" list="haEntitySuggestions" placeholder="sensor.outdoor_temperature"></label>
<p class="field-note" data-i18n="zones.outdoorSensorHelp">Leave empty to use the global Outdoor temperature
entity_id. Set another entity_id to use a different outdoor sensor only for this zone. It is used by
outdoor-temperature assist and recorded in history/metrics.</p>
<div class="two"><label><span data-i18n="zones.minAdjust">Minimum adjustment interval (s)</span><input
type="number" min="15" name="min_adjust_seconds" value="120"></label><label><span
data-i18n="zones.standbyOffset">Standby setpoint offset °C</span><input type="text" inputmode="decimal"
@@ -1641,7 +1784,8 @@
<dialog id="generatedTokenDialog" class="auth-dialog">
<div class="dialog-form">
<div class="dialog-head">
<h2 data-i18n="settings.tokenCreated">Token created</h2><button type="button" data-close data-ui-icon="close"></button>
<h2 data-i18n="settings.tokenCreated">Token created</h2><button type="button" data-close
data-ui-icon="close"></button>
</div>
<p class="field-note" data-i18n="settings.tokenCreatedHint">Copy this token now. It will not be shown again.</p>
<label><span data-i18n="auth.token">Access token</span><input id="generatedAccessToken" class="mono"
@@ -1655,18 +1799,27 @@
<dialog id="outdoorHistoryDialog" class="dialog-wide outdoor-history-dialog">
<div class="dialog-form">
<div class="dialog-head">
<div><span class="eyebrow" data-i18n="history.24h">24 hours</span><h2 data-i18n="history.allOutdoor">Outdoor temperatures</h2></div>
<button type="button" data-close data-i18n-aria="actions.close" aria-label="Close" data-ui-icon="close"></button>
<div><span class="eyebrow" data-i18n="history.24h">24 hours</span>
<h2 data-i18n="history.allOutdoor">Outdoor temperatures</h2>
</div>
<button type="button" data-close data-i18n-aria="actions.close" aria-label="Close"
data-ui-icon="close"></button>
</div>
<div class="outdoor-history-current"><small data-i18n="house.outdoor">Outdoor</small><strong id="outdoorHistoryCurrent">--</strong></div>
<div class="outdoor-history-current"><small data-i18n="house.outdoor">Outdoor</small><strong
id="outdoorHistoryCurrent">--</strong></div>
<div id="outdoorHistoryChartHost"></div>
<div class="outdoor-history-links" data-i18n-aria="house.outdoorHistoryMore" aria-label="More metrics and ranges in history">
<div class="outdoor-history-links" data-i18n-aria="house.outdoorHistoryMore"
aria-label="More metrics and ranges in history">
<span data-i18n="house.outdoorHistoryMore">More in history</span>
<div>
<a href="/history/overview?hours=168" data-history-route data-history-hours="168" data-i18n="history.range7d">7 days</a>
<a href="/history/overview?hours=720" data-history-route data-history-hours="720" data-i18n="history.range30d">30 days</a>
<a href="/history/overview?hours=8760" data-history-route data-history-hours="8760" data-i18n="history.range1y">1 year</a>
<a href="/history/overview" data-history-route class="outdoor-history-all" data-i18n="house.outdoorHistoryFull">Full history</a>
<a href="/history/overview?hours=168" data-history-route data-history-hours="168"
data-i18n="history.range7d">7 days</a>
<a href="/history/overview?hours=720" data-history-route data-history-hours="720"
data-i18n="history.range30d">30 days</a>
<a href="/history/overview?hours=8760" data-history-route data-history-hours="8760"
data-i18n="history.range1y">1 year</a>
<a href="/history/overview" data-history-route class="outdoor-history-all"
data-i18n="house.outdoorHistoryFull">Full history</a>
</div>
</div>
</div>
@@ -1695,8 +1848,8 @@
data-i18n="debug.requests">Requests</button>
<button type="button" role="tab" aria-selected="false" data-debug-filter="gree"
data-i18n="debug.gree">GREE</button>
<button type="button" role="tab" aria-selected="false" data-debug-filter="cloud"
data-i18n="debug.cloud">Cloud API</button>
<button type="button" role="tab" aria-selected="false" data-debug-filter="cloud" data-i18n="debug.cloud">Cloud
API</button>
<button type="button" role="tab" aria-selected="false" data-debug-filter="mqtt"
data-i18n="debug.mqtt">MQTT</button>
</div>