Files
gree-controller/web/index.html
T

1679 lines
114 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<meta name="theme-color" content="#151515" id="themeColorMeta">
<meta name="description" content="Local GREE air conditioner controller" data-i18n-content="meta.description">
<link rel="manifest" href="__GREE_BASE_PATH__/manifest.webmanifest">
<link rel="icon" href="__GREE_BASE_PATH__/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="__GREE_STYLES_ASSET__">
<script src="__GREE_THEME_INIT_ASSET__"></script>
<script src="__GREE_LANG_INIT_ASSET__"></script>
<title>GREE Controller</title>
</head>
<body>
<header class="topbar">
<div class="brand">
<div class="brand-line"><strong>GREE Controller</strong><small id="connectionLabel"
class="connection-dot connecting" role="status" aria-label="Connecting" title="Connecting"></small></div>
</div>
<div class="toolbar-runtime-status" id="toolbarRuntimeStatus" aria-live="polite">0/0</div>
<div class="top-actions">
<div class="toolbar-picker" data-i18n-title="controls.language" title="Language">
<span class="toolbar-picker-value" id="languageLabel" aria-hidden="true">EN</span>
<span class="toolbar-picker-chevron" aria-hidden="true"></span>
<select class="toolbar-picker-select" id="languageSelect" data-i18n-aria="controls.language"
aria-label="Language">
<option value="en">English</option>
</select>
</div>
<div class="toolbar-picker" data-i18n-title="controls.theme" title="Theme">
<span class="toolbar-picker-value theme-picker-value" id="themeIcon" aria-hidden="true"></span>
<span class="toolbar-picker-chevron" 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>
<option value="light" data-i18n="theme.light">Light</option>
<option value="dark" data-i18n="theme.dark">Dark</option>
</select>
</div>
<button class="icon-button toolbar-icon-control" id="refreshButton" data-i18n-title="actions.refresh"
data-i18n-aria="actions.refresh" title="Refresh" aria-label="Refresh"></button>
</div>
<div class="connection-banner" id="connectionBanner" role="status" aria-live="polite" hidden>
<span class="connection-banner-dot" aria-hidden="true"></span>
<div><strong id="connectionBannerTitle">Disconnected</strong><span id="connectionBannerText">Live updates are
unavailable. Displayed data may be stale.</span></div>
<button class="secondary" type="button" id="connectionRetry" data-i18n="actions.retry">Retry</button>
</div>
<div class="simulation-mode-banner" id="simulationModeBanner" role="status" aria-live="polite" hidden>
<strong data-i18n="simulation.bannerTitle">SIMULATION MODE</strong>
<span data-i18n="simulation.bannerText">Simulation is enabled. Verify the mode before relying on controller
output.</span>
</div>
</header>
<main>
<section class="view active" data-view="dashboard">
<nav class="dashboard-tabs" data-i18n-aria="dashboard.sections" aria-label="Dashboard sections">
<button type="button" class="active" data-dashboard-tab="main" data-i18n="dashboard.tabMain">Main</button>
<button type="button" data-dashboard-tab="thermostats" data-i18n="dashboard.tabThermostats">Thermostats</button>
<button type="button" data-dashboard-tab="manual" data-i18n="dashboard.tabManual">Manual control</button>
</nav>
<div class="dashboard-tab-panel active" data-dashboard-panel="main">
<div class="hero dashboard-summary-card">
<div class="dashboard-summary-copy"><span class="eyebrow" data-i18n="dashboard.home">Home</span>
<h1 data-i18n="dashboard.title">Comfort under control</h1>
<p id="summaryText" data-i18n="dashboard.loading">Loading devices…</p>
</div>
<div class="dashboard-summary-status">
<div class="metrics" id="metrics"></div>
<div class="hero-temp" id="heroTemperature">--<small>°C</small></div>
</div>
</div>
<div class="panel dashboard-global-panel">
<div class="dashboard-global-power">
<div><span class="eyebrow" data-i18n="house.powerAllEyebrow">Global power</span>
<h3 data-i18n="house.powerAllTitle">All air conditioners</h3>
<p data-i18n="house.powerAllHint">Bulk power action for all units. OFF leaves thermostats locally off
until you explicitly turn a thermostat, group or the whole house back on.</p>
</div>
<div class="house-power-actions"><button id="housePowerOn" type="button" class="secondary"
data-action="house-power" data-value="true" data-i18n="house.powerOnAll">Turn all on</button><button
id="housePowerOff" type="button" class="secondary" data-action="house-power" data-value="false"
data-i18n="house.powerOffAll">Turn all off</button></div>
</div>
<div class="dashboard-global-divider"></div>
<div class="house-climate dashboard-house-climate" id="houseClimate"></div>
</div>
<section class="panel dashboard-section-panel" id="controlPlanSection">
<div class="dashboard-section-head compact-head">
<div><span class="eyebrow" data-i18n="plan.eyebrow">Control plan</span>
<h2 data-i18n="plan.title">What happens next</h2>
</div>
</div>
<div class="automation-plan-grid" id="controlPlan"></div>
</section>
</div>
<div class="dashboard-tab-panel" data-dashboard-panel="thermostats" hidden>
<section class="dashboard-primary-section">
<div class="dashboard-section-head">
<div><span class="eyebrow" data-i18n="groups.eyebrow">Group control</span>
<h2 data-i18n="groups.dashboardTitle">Control selected air conditioners</h2>
<p data-i18n="groups.dashboardHint">Group ON activates its thermostats; Group OFF powers its units down
and releases group ownership. You can also choose a mode, preset, or custom temperature.</p>
</div>
<div class="dashboard-section-actions"><span class="badge" id="dashboardGroupCount">0</span><button
type="button" class="secondary" data-go="groups" data-i18n="groups.manage">Manage groups</button></div>
</div>
<div class="group-quick-grid dashboard-group-strip" id="dashboardGroups"></div>
</section>
<section class="panel dashboard-section-panel dashboard-thermostat-section">
<div class="dashboard-section-head compact-head">
<div><span class="eyebrow" data-i18n="nav.zones">Zones</span>
<h2 data-i18n="dashboard.thermostats">Thermostats</h2>
</div>
<div class="dashboard-section-actions"><button type="button" class="secondary queue-overview-button"
data-action="open-compressor-queue"><span data-i18n="zones.queueOverview">Queue</span><b
class="queue-overview-count" data-compressor-queue-count>0</b></button><span class="badge"
id="dashboardZoneCount">0</span></div>
</div>
<div class="list-grid dashboard-zones" id="dashboardZones"></div>
</section>
</div>
<div class="dashboard-tab-panel" data-dashboard-panel="manual" hidden>
<section class="panel dashboard-section-panel">
<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>
</div>
<span class="badge" id="dashboardDeviceCount">0</span>
</div>
<div class="device-grid" id="dashboardDevices"></div>
</section>
</div>
</section>
<section class="view" data-view="devices">
<div class="section-heading">
<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>
<p class="lead" data-i18n="devices.technicalDescription">Technical configuration and diagnostics only. Current
operating settings are available in Manual control.</p>
<div id="deviceGroupsSummary" class="device-installation-summary"></div>
<div class="device-grid" id="deviceList"></div>
</section>
<section class="view" data-view="zones">
<div class="section-heading">
<div><span class="eyebrow" data-i18n="zones.automation">Automation</span>
<h1 data-i18n="nav.zones">Zones</h1>
</div>
<div class="section-heading-actions"><button type="button" class="secondary queue-overview-button"
data-action="open-compressor-queue"><span data-i18n="zones.queueOverview">Queue</span><b
class="queue-overview-count" data-compressor-queue-count>0</b></button><button class="secondary"
data-open="zoneDialog" data-i18n="zones.new">New zone</button></div>
</div>
<p class="lead" data-i18n="zones.description">Zones define thermostat logic and sensor configuration. Use Quick
thermostats on the Dashboard for current temperature changes and presets.</p>
<div class="list-grid" id="zoneList"></div>
</section>
<section class="view" data-view="groups">
<div class="section-heading">
<div><span class="eyebrow" data-i18n="groups.eyebrow">Group control</span>
<h1 data-i18n="nav.groups">Groups</h1>
</div><button class="secondary" data-open="groupDialog" data-i18n="groups.new">New group</button>
</div>
<p class="lead" data-i18n="groups.description">Combine thermostat zones and control only that set. Turning a group
on activates its thermostats; turning it off powers its units down and releases group ownership.</p>
<div class="list-grid" id="groupList"></div>
</section>
<section class="view" data-view="flows">
<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>
<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>
<button type="button" data-go="schedules" data-i18n="nav.schedules">Schedules</button>
<button type="button" data-go="automations" data-i18n="nav.automations">Automations</button>
</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>
<span class="badge" data-i18n="flow.sourceOfTruth">Flow = source of truth</span>
</div>
<section class="flow-list-section">
<div class="flow-list-heading flow-list-heading-count"><span id="flowListCount" class="badge"></span></div>
<div class="list-grid" id="flowList"></div>
</section>
</section>
<section class="view" data-view="schedules">
<div class="section-heading">
<div><span class="eyebrow" data-i18n="schedules.calendar">Calendar</span>
<h1 data-i18n="nav.schedules">Schedules</h1>
</div><button class="secondary" data-open="scheduleDialog" data-i18n="actions.add">Add</button>
</div>
<nav class="automation-tabs" data-i18n-aria="automationHub.navigation" aria-label="Automation navigation">
<button type="button" data-go="flows" data-i18n="nav.flows">Flow</button>
<button type="button" class="active" data-go="schedules" data-i18n="nav.schedules">Schedules</button>
<button type="button" data-go="automations" data-i18n="nav.automations">Automations</button>
</nav>
<div class="panel schedule-template-panel">
<div>
<h3 data-i18n="schedules.quickSetup">Quick schedule setup</h3>
<p class="field-note" data-i18n="schedules.quickSetupHint">Choose a zone and a ready-made daily rhythm. You
can edit every generated entry afterwards.</p>
</div>
<select id="schedulePresetZone"></select>
<div class="template-grid">
<button class="secondary" data-schedule-template="family" data-i18n="schedules.templateFamily">Family</button>
<button class="secondary" data-schedule-template="child" data-i18n="schedules.templateChild">Child
room</button>
<button class="secondary" data-schedule-template="bedroom"
data-i18n="schedules.templateBedroom">Bedroom</button>
<button class="secondary" data-schedule-template="workday"
data-i18n="schedules.templateWorkday">Workday</button>
<button class="secondary" data-schedule-template="always" data-i18n="schedules.templateAlways">Always
comfort</button>
</div>
</div>
<div class="list-grid" id="scheduleList"></div>
</section>
<section class="view" data-view="automations">
<div class="section-heading">
<div><span class="eyebrow" data-i18n="automations.rules">Rules</span>
<h1 data-i18n="nav.automations">Automations</h1>
</div><button class="secondary" data-open="automationDialog" data-i18n="actions.add">Add</button>
</div>
<nav class="automation-tabs" data-i18n-aria="automationHub.navigation" aria-label="Automation navigation">
<button type="button" data-go="flows" data-i18n="nav.flows">Flow</button>
<button type="button" data-go="schedules" data-i18n="nav.schedules">Schedules</button>
<button type="button" class="active" data-go="automations" data-i18n="nav.automations">Automations</button>
</nav>
<div class="panel automation-hint"><strong data-i18n="automations.smartHintTitle">Use thermostat presets for daily
comfort</strong>
<p data-i18n="automations.smartHint">Schedules and zone presets handle normal heating/cooling automatically.
Keep automations for special exceptions so they do not fight the thermostat.</p>
</div>
<div class="list-grid" id="automationList"></div>
</section>
<section class="view" data-view="simulation">
<div class="section-heading simulation-page-head">
<div><span class="eyebrow" data-i18n="simulation.eyebrow">Simulator</span>
<h1 data-i18n="simulation.title">Automation simulator</h1>
</div>
<div class="simulation-head-actions"><button class="secondary" id="simulationOpenTab"
data-i18n="simulation.openTab">Open only simulator in new tab</button><button class="secondary"
id="simulationFullscreen" data-i18n="simulation.fullscreen">Full screen</button></div>
</div>
<p class="lead" data-i18n="simulation.description">Live preview of the thermostat and automation logic. The flow
board shows how sensor readings, schedules, night mode and thermostat decisions become commands sent to each
GREE unit.</p>
<div class="panel simulation-scope-toolbar"><label><span data-i18n="simulation.viewBy">View by</span><select
id="simulationScope">
<option value="units" data-i18n="simulation.unitsView">Individual units</option>
<option value="groups" data-i18n="simulation.groupsView">Groups</option>
</select></label><label><span data-i18n="simulation.show">Show</span><select
id="simulationTarget"></select></label></div>
<div class="simulation-summary-grid" id="simulationSummary"></div>
<section class="panel simulation-section-panel" aria-labelledby="simulationFlowTitle">
<div class="simulation-panel-head">
<div><span class="eyebrow" data-i18n="simulation.flowEyebrow">Live flow</span>
<h2 id="simulationFlowTitle" data-i18n="simulation.flowTitle">Automation flow board</h2>
</div>
<div class="flow-legend"><span><i class="flow-legend-dot input"></i><b
data-i18n="simulation.legendInput">Input</b></span><span><i class="flow-legend-dot logic"></i><b
data-i18n="simulation.legendLogic">Logic</b></span><span><i class="flow-legend-dot action"></i><b
data-i18n="simulation.legendAction">Action</b></span></div>
</div>
<div class="simulation-flow-scroll">
<div class="simulation-flow-board" id="simulationFlowBoard"></div>
</div>
</section>
<section class="panel simulation-section-panel" aria-labelledby="simulationTimelineTitle">
<div class="simulation-panel-head">
<div><span class="eyebrow" data-i18n="simulation.timelineEyebrow">Timeline</span>
<h2 id="simulationTimelineTitle" data-i18n="simulation.timelineTitle">What will happen next</h2>
</div>
</div>
<div class="simulation-panel-body">
<div class="simulation-timeline" id="simulationTimeline"></div>
</div>
</section>
<section class="panel simulation-section-panel" aria-labelledby="simulationRulesTitle">
<div class="simulation-panel-head">
<div><span class="eyebrow" data-i18n="simulation.rulesEyebrow">Rules</span>
<h2 id="simulationRulesTitle" data-i18n="simulation.rulesTitle">Automation rules</h2>
</div>
</div>
<div class="simulation-panel-body">
<div class="simulation-rules-grid" id="simulationRules"></div>
</div>
</section>
</section>
<section class="view" data-view="history">
<div class="section-heading">
<div><span class="eyebrow" data-i18n="history.measurements">Measurements</span>
<h1 data-i18n="history.title">Climate history</h1>
</div>
</div>
<div class="history-tabs" id="historyTabs" role="tablist">
<button data-history-tab="overview" data-i18n="history.tabOverview">Overview</button>
<button data-history-tab="zones" data-i18n="history.tabZones">Zones</button>
<button data-history-tab="devices" data-i18n="history.tabDevices">GREE devices</button>
<button data-history-tab="energy" data-i18n="energy.title">Energy</button>
<button data-history-tab="network" data-i18n="history.tabNetwork">Pings</button>
<button data-history-tab="sensors" data-i18n="history.tabSensors">HA sensors</button>
<button data-history-tab="custom" data-i18n="history.tabCustom">Custom chart</button>
</div>
<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">
<option value="6" data-i18n="history.6h">6 hours</option>
<option value="24" selected 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="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>
<button class="secondary history-refresh-button" id="historyRefresh"
data-i18n="actions.refresh">Refresh</button>
</div>
<div class="history-summary" id="historySummary"></div>
</div>
<div id="historyCustomBuilder" class="history-custom-builder"></div>
<div id="historyCharts" class="history-charts"></div>
</section>
<section class="view" data-view="night">
<div class="section-heading">
<div><span class="eyebrow" data-i18n="night.eyebrow">Comfort</span>
<h1 data-i18n="nav.nightMode">Night mode</h1>
</div>
</div>
<p class="lead" data-i18n="night.description">Configure quieter thermostat behavior for sleeping hours without
mixing it with application settings.</p>
<form class="settings-form standalone-settings-form" id="nightModeForm">
<section class="panel settings-block">
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.nightMode">Night mode</h3>
<p data-i18n="settings.nightModeHint">During selected hours the thermostat limits fan speed and can
request Quiet on supported units.</p>
</div>
</div>
<div class="settings-grid">
<label class="check wide"><input type="checkbox" name="night_mode_enabled"> <span
data-i18n="settings.nightModeEnabled">Enable night mode</span></label>
<label><span data-i18n="settings.nightStart">Start</span><input type="time" name="night_mode_start"
value="22:00"></label>
<label><span data-i18n="settings.nightEnd">End</span><input type="time" name="night_mode_end"
value="06:00"></label>
<label><span data-i18n="settings.nightMaxFan">Maximum fan speed</span><select
name="night_mode_max_fan_speed">
<option value="1" data-i18n="fan.low">Low</option>
<option value="2" data-i18n="fan.mediumLow">Medium-low</option>
<option value="3" data-i18n="fan.medium">Medium</option>
<option value="4" data-i18n="fan.mediumHigh">Medium-high</option>
<option value="5" data-i18n="fan.high">High</option>
</select></label>
<label class="check"><input type="checkbox" name="night_mode_force_quiet"> <span
data-i18n="settings.nightForceQuiet">Use Quiet when supported</span></label>
<label class="check wide"><input type="checkbox" name="night_mode_native_sleep"> <span
data-i18n="settings.nightNativeSleep">Use native Sleep when supported</span></label>
</div>
</section>
<div class="settings-save-bar"><span data-i18n="night.saveHint">Save night-mode changes.</span><button
class="primary" type="submit" data-i18n="actions.save">Save</button></div>
</form>
</section>
<section class="view" data-view="homeassistant">
<div class="section-heading">
<div><span class="eyebrow" data-i18n="homeAssistant.eyebrow">Integration</span>
<h1 data-i18n="nav.homeAssistant">Home Assistant / Sensors</h1>
</div>
</div>
<p class="lead" data-i18n="homeAssistant.description">Connection, temperature sensors, friendly aliases and access
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-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>
</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-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>
</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>
</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="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>
</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>
</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>
</form>
</section>
<section class="view" data-view="settings">
<div class="section-heading">
<div><span class="eyebrow" data-i18n="settings.system">System</span>
<h1 data-i18n="nav.settings">Settings</h1>
</div>
</div>
<div class="settings-mode-tabs" role="tablist" data-i18n-aria="settings.settingsSections"
aria-label="Settings sections">
<button type="button" class="active" role="tab" aria-selected="true" data-settings-tab="app"
data-i18n="settings.applicationSettings">Application</button>
<button type="button" role="tab" aria-selected="false" data-settings-tab="gree"
data-i18n="settings.greeSettings">GREE</button>
<button type="button" role="tab" aria-selected="false" data-settings-tab="cloud">GREE Cloud</button>
</div>
<form class="settings-form" id="settingsForm" novalidate>
<div class="settings-pane" data-settings-pane="app">
<section class="panel settings-block">
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.applicationRuntime">Application runtime</h3>
<p data-i18n="settings.applicationRuntimeHint">Application-wide behavior that does not change GREE
transport or discovery.</p>
</div>
</div>
<div class="settings-grid">
<label class="check wide"><input type="checkbox" name="simulator_enabled"> <span
data-i18n="settings.simulationMode">Simulation mode</span></label>
<p class="field-note wide warning-note" data-i18n="settings.simulationModeHint">When enabled, a prominent
warning is shown throughout the application.</p>
</div>
</section>
<section class="panel settings-block">
<div class="settings-block-head">
<div>
<h3 data-i18n="notifications.title">Notifications</h3>
<p data-i18n="notifications.hint">Send important events or only problems/anomalies.</p>
</div>
</div>
<div class="settings-grid">
<label class="check wide"><input type="checkbox" name="notifications_enabled"> <span
data-i18n="notifications.enable">Enable notifications</span></label>
<label><span data-i18n="notifications.mode">Mode</span><select name="notifications_mode">
<option value="problems" data-i18n="notifications.problems">Errors and anomalies only</option>
<option value="important" data-i18n="notifications.important">Important events + problems</option>
</select></label>
<label><span data-i18n="notifications.provider">Provider</span><select name="notifications_provider">
<option value="pushover">Pushover</option>
<option value="slack">Slack</option>
<option value="discord">Discord</option>
</select></label>
<div class="wide notification-provider" data-notification-provider="pushover"><label><span
data-i18n="notifications.pushoverToken">Pushover application token</span><input type="password"
name="pushover_app_token" autocomplete="new-password" data-i18n-placeholder="settings.secretKeep"
placeholder="Leave empty to keep saved secret"></label><label><span
data-i18n="notifications.pushoverUser">Pushover user/group key</span><input type="password"
name="pushover_user_key" autocomplete="new-password" data-i18n-placeholder="settings.secretKeep"
placeholder="Leave empty to keep saved secret"></label></div>
<label class="wide notification-provider" data-notification-provider="slack"><span
data-i18n="notifications.slackWebhook">Slack incoming webhook</span><input type="password"
name="slack_webhook_url" autocomplete="new-password"
placeholder="https://hooks.slack.com/services/…"></label>
<label class="wide notification-provider" data-notification-provider="discord"><span
data-i18n="notifications.discordWebhook">Discord webhook</span><input type="password"
name="discord_webhook_url" autocomplete="new-password"
placeholder="https://discord.com/api/webhooks/…"></label>
<label><span data-i18n="notifications.cooldown">Cooldown (s)</span><input type="number"
name="notification_cooldown_seconds" min="30" max="86400" value="300"></label>
<label><span data-i18n="notifications.failureThreshold">Communication failures before alert</span><input
type="number" name="notification_failure_threshold" min="2" max="100" value="3"></label>
<label><span data-i18n="notifications.targetTimeout">Target not reached timeout (min)</span><input
type="number" name="notification_target_timeout" min="5" max="1440" value="60"></label>
<fieldset class="notification-alert-types wide">
<legend data-i18n="notifications.alertTypes">Alert types</legend>
<p class="field-note" data-i18n="notifications.alertTypesHint">Choose exactly which alerts may be
delivered. Thresholds above still define when applicable alerts are raised.</p>
<div class="notification-alert-grid">
<label class="check"><input type="checkbox" name="notification_alert_stale_sensor"> <span
data-i18n="notifications.alertStaleSensor">Stale Home Assistant sensor readings</span></label>
<label class="check"><input type="checkbox" name="notification_alert_sensor_errors"> <span
data-i18n="notifications.alertSensorErrors">Other Home Assistant sensor errors</span></label>
<label class="check"><input type="checkbox" name="notification_alert_communication"> <span
data-i18n="notifications.alertCommunication">Device communication problems</span></label>
<label class="check"><input type="checkbox" name="notification_alert_target_timeout"> <span
data-i18n="notifications.alertTargetTimeout">Target temperature timeout</span></label>
<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>
<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
data-i18n="notifications.alertImportantEvents">Important state changes</span></label>
<label class="check"><input type="checkbox" name="notification_alert_other"> <span
data-i18n="notifications.alertOther">Other warnings and errors</span></label>
</div>
</fieldset>
<div class="form-actions wide"><button type="button" class="secondary" id="testNotifications"
data-i18n="notifications.test">Send test notification</button></div>
</div>
</section>
<section class="panel settings-block">
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.metricsAndLogs">Metrics and logs</h3>
<p data-i18n="settings.compactionHint">SQLite keeps recent data locally and compacts older samples to
the resolution used by charts.</p>
</div>
</div>
<div class="settings-grid">
<label><span data-i18n="settings.retentionDays">Local metric retention (days)</span><input type="number"
name="history_retention_days" min="1" max="3650" required></label>
<label><span data-i18n="settings.eventRetentionDays">Event/log retention (days)</span><input type="number"
name="event_log_retention_days" min="1" max="3650" required></label>
<label class="check wide"><input type="checkbox" name="history_compaction_enabled"> <span
data-i18n="settings.compaction">Compact old metrics</span></label>
</div>
</section>
<section class="panel settings-block">
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.influx">Long-term InfluxDB history</h3>
<p data-i18n="settings.influxHint">Optional archive for older history. InfluxDB 1.x and 2.x are
supported.</p>
</div>
</div>
<div class="settings-grid">
<label class="check wide"><input type="checkbox" name="influx_enabled"> <span
data-i18n="settings.influxEnabled">Enable InfluxDB archive</span></label>
<label><span data-i18n="settings.influxVersion">InfluxDB version</span><select name="influx_version">
<option value="1">1.x</option>
<option value="2">2.x</option>
</select></label>
<label><span data-i18n="settings.influxThreshold">Use archive for history older than (days)</span><input
type="number" name="influx_threshold_days" min="1" max="3650" value="30"></label>
<label class="wide"><span>URL</span><input type="url" name="influx_url"
placeholder="http://influxdb:8086"></label>
<div class="wide influx-fields" data-influx-fields="1">
<label><span data-i18n="settings.influxDatabase">Database</span><input name="influx_database"
placeholder="gree_controller"></label>
<label><span data-i18n="settings.influxUsername">Username</span><input name="influx_username"></label>
<label><span data-i18n="settings.influxPassword">Password</span><input type="password"
name="influx_password" autocomplete="new-password" data-i18n-placeholder="settings.secretKeep"
placeholder="Leave empty to keep saved secret"></label>
</div>
<div class="wide influx-fields" data-influx-fields="2">
<label><span data-i18n="settings.influxOrg">Organization</span><input name="influx_org"></label>
<label><span data-i18n="settings.influxBucket">Bucket</span><input name="influx_bucket"
placeholder="gree_controller"></label>
<label><span data-i18n="settings.influxToken">Token</span><input type="password" name="influx_token"
autocomplete="new-password" data-i18n-placeholder="settings.secretKeep"
placeholder="Leave empty to keep saved secret"></label>
</div>
</div>
</section>
<section class="panel settings-block">
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.debug">On-screen debug</h3>
<p data-i18n="settings.debugHint">Live diagnostics displayed on every application page.</p>
</div>
</div>
<div class="settings-grid">
<label class="check"><input type="checkbox" name="debug_overlay_enabled"> <span
data-i18n="settings.debugOverlay">Show debug window on every page</span></label>
<label class="check"><input type="checkbox" name="debug_gree_frames"> <span
data-i18n="settings.debugGreeFrames">Include GREE protocol frames</span></label>
<label class="check"><input type="checkbox" name="debug_cloud_requests"> <span
data-i18n="settings.debugCloudRequests">Trace GREE Cloud API requests</span></label>
<label class="check"><input type="checkbox" name="debug_cloud_mqtt"> <span
data-i18n="settings.debugCloudMqtt">Trace GREE Cloud MQTT</span></label>
</div>
</section>
<section class="panel settings-block">
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.backup">Configuration backup</h3>
<p class="warning-note" data-i18n="settings.backupHint">Export/import application configuration.
Exported files can contain GREE device keys plus Home Assistant and InfluxDB secrets; metrics and API
access tokens are not included.</p>
</div>
</div>
<div class="form-actions backup-actions"><button type="button" class="secondary" id="exportSettings"
data-i18n="settings.export">Export settings</button><button type="button" class="secondary"
id="importSettings" data-i18n="settings.import">Import settings</button><input type="file"
id="importSettingsFile" accept="application/json,.json" hidden></div>
</section>
<div class="panel system-panel" id="systemInfo"></div>
</div>
<div class="settings-pane" data-settings-pane="gree" hidden>
<section class="panel settings-block">
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.greeConnection">GREE connection</h3>
<p data-i18n="settings.greeConnectionHint">Controller identity, polling intervals and LAN discovery
transport.</p>
</div>
</div>
<div class="settings-grid">
<label><span data-i18n="settings.clientId">Client identifier</span><input name="controller_id"
required></label>
<label><span data-i18n="settings.pollInterval">Poll interval (s)</span><input type="number"
name="poll_interval_seconds" min="2" max="3600" required></label>
<label><span data-i18n="settings.zoneInterval">Zone interval (s)</span><input type="number"
name="zone_interval_seconds" min="2" max="3600" required></label>
<label><span data-i18n="settings.broadcast">Broadcast address</span><input name="discovery_broadcast"
placeholder="255.255.255.255:7000" required></label>
<label><span data-i18n="settings.discoveryTimeout">Discovery timeout (ms)</span><input type="number"
name="discovery_timeout_ms" min="300" max="30000" required></label>
</div>
</section>
<section class="panel settings-block">
<div class="settings-block-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>
</div>
</div>
<div class="settings-grid">
<label class="check wide"><input type="checkbox" name="ping_metrics_enabled"> <span data-i18n="settings.connectivityEnable">Enable local connectivity metrics</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 settings-block">
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.greeCommands">GREE commands</h3>
<p data-i18n="settings.suppressBeepHint">Only changed properties are sent. Buzzer suppression is also
requested when supported by the unit firmware.</p>
</div>
</div>
<div class="settings-grid">
<label class="check wide"><input type="checkbox" name="suppress_device_beep"> <span
data-i18n="settings.suppressBeep">Try to suppress command beeps</span></label>
<label class="check wide"><input type="checkbox" name="compressor_protection_enabled"> <span
data-i18n="settings.compressorProtection">Compressor protection</span></label>
<label><span data-i18n="settings.compressorProtectionTime">Protection time (min)</span><input
type="number" name="compressor_protection_minutes" min="0.5" max="30" step="0.5" value="3"></label>
<p class="field-note wide" data-i18n="settings.compressorProtectionHint">Recommended: 3 minutes. Starts
and Heat/Cool changes requested during the protection window are queued and can be cancelled from
Thermostats.</p>
</div>
</section>
<section class="panel settings-block">
<div class="settings-block-head">
<div>
<h3 data-i18n="settings.greeTraffic">GREE traffic</h3>
<p data-i18n="settings.greeTrafficHint">Live counters of UDP frames received from configured air
conditioners since controller startup.</p>
</div>
</div>
<div id="greeFrameStats" class="gree-frame-stats"></div>
</section>
</div>
<div class="settings-pane" data-settings-pane="cloud" hidden>
<section class="panel settings-block">
<div class="settings-block-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="settings-grid">
<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="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.cloudConnectivityHint">Optional. Disabled by default. Measures REST login response and MQTT PINGRESP round-trip.</p>
<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.cloudBroker">Broker</span><strong id="greeCloudBroker"></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>
</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>
</div>
<div class="settings-save-bar"><span data-i18n="settings.saveHint">Save changes made in the blocks
above.</span><button class="primary" type="submit" data-i18n="actions.save">Save</button></div>
</form>
</section>
<section class="view" data-view="logs">
<div class="section-heading">
<div><span class="eyebrow" data-i18n="logs.diagnostics">Diagnostics</span>
<h1 data-i18n="nav.logs">Events</h1>
</div><button class="secondary" id="logsRefresh" data-i18n="actions.refresh">Refresh</button>
</div>
<div class="panel logs-toolbar">
<div><strong data-i18n="logs.retention">Log retention</strong><small data-i18n="logs.retentionHint">Old event
rows are removed automatically during maintenance.</small></div><label><span
data-i18n="logs.level">Level</span><select id="logLevelFilter">
<option value="all" data-i18n="logs.all">All</option>
<option value="error" data-i18n="logs.errors">Errors</option>
<option value="warn" data-i18n="logs.warnings">Warnings</option>
<option value="info" data-i18n="logs.info">Info</option>
</select></label><label><span data-i18n="logs.category">Category</span><select id="logCategoryFilter">
<option value="all" data-i18n="logs.all">All</option>
<option value="device" data-i18n="nav.devices">Devices</option>
<option value="zone" data-i18n="nav.zones">Thermostats</option>
<option value="automation" data-i18n="nav.automations">Automations</option>
<option value="settings" data-i18n="nav.settings">Settings</option>
<option value="integration" data-i18n="logs.integrations">Integrations</option>
<option value="system" data-i18n="logs.systemOther">System/other</option>
</select></label><label><span data-i18n="logs.keepFor">Keep for</span><select id="logRetentionDays">
<option value="7" data-i18n="logs.days7">7 days</option>
<option value="14" data-i18n="logs.days14">14 days</option>
<option value="30" data-i18n="logs.days30">30 days</option>
<option value="90" data-i18n="logs.days90">90 days</option>
<option value="180" data-i18n="logs.days180">180 days</option>
<option value="365" data-i18n="logs.days365">365 days</option>
</select></label><button class="secondary" id="saveLogRetention" data-i18n="actions.save">Save</button>
</div>
<div class="panel log-list" id="logList"></div>
</section>
</main>
<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"
data-i18n-title="flow.fitView" title="Fit">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.previewDetails">Interpretation and Flow cycle</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 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="menu-list">
<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-logs"><span data-i18n="flow.logs">Logs</span><span></span></button>
</div>
</dialog>
<input id="flowImportFile" type="file" accept="application/json,.json,.flow.json" hidden>
<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>
<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>
<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>
<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="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="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>
</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 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>
</div>
<div id="flowTestResults" class="flow-test-results"></div>
</div>
</dialog>
<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></span><b data-i18n="nav.dashboard">Dashboard</b></button>
<button data-nav="zones"><span></span><b data-i18n="nav.zones">Zones</b></button>
<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>
<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="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>
<button class="mobile-nav-only" data-nav="more"><span>•••</span><b data-i18n="nav.more">More</b></button>
</nav>
<dialog id="moreDialog" class="sheet">
<div class="dialog-head">
<h2 data-i18n="nav.more">More</h2><button data-close>×</button>
</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></span></button>
<button data-go="groups"><span data-i18n="nav.groups">Groups</span><span></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></span></button>
<button data-go="automations"><span data-i18n="nav.automations">Automations</span><span></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></span></button>
<button data-go="night"><span data-i18n="nav.nightMode">Night mode</span><span></span></button>
<button data-go="homeassistant"><span data-i18n="nav.homeAssistant">Home Assistant /
Sensors</span><span></span></button>
<button data-go="settings"><span data-i18n="nav.settings">Settings</span><span></span></button>
<button data-go="logs"><span data-i18n="nav.logsAndEvents">Events and logs</span><span></span></button>
</div>
</dialog>
<dialog id="deviceDialog">
<form method="dialog" id="deviceForm" class="dialog-form">
<div class="dialog-head">
<h2 data-i18n="devices.add">Add device</h2><button type="button" data-close>×</button>
</div>
<label><span data-i18n="common.name">Name</span><input name="name" required
data-i18n-placeholder="placeholder.livingRoom" placeholder="Living room"></label>
<label><span>MAC / CID</span><input name="mac" required placeholder="AABBCCDDEEFF"></label>
<label><span data-i18n="devices.ipAddress">IP address</span><input name="ip" required
placeholder="192.168.1.50"></label>
<div class="two"><label><span>Port</span><input type="number" name="port" value="7000" min="1"
max="65535"></label><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></div>
<label><span data-i18n="devices.keyOptional">Key (optional)</span><input name="key"
data-i18n-placeholder="devices.keyPlaceholder" placeholder="Leave empty for automatic bind"></label>
<label class="check"><input type="checkbox" name="simulated"> <span data-i18n="devices.simulated">Simulated
device</span></label>
<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.add">Add</button></div>
</form>
</dialog>
<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>×</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>
</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>×</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>
<label><span data-i18n="discovery.protocol">Discovery 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>
<div class="two"><label><span data-i18n="discovery.passes">Scan passes</span><input type="number" name="passes"
min="1" max="10" value="3"></label><label><span data-i18n="discovery.timeout">Total scan time
(ms)</span><input type="number" name="timeout_ms" min="500" max="30000" value="6000"></label></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.discover">Discover</button></div>
</form>
</dialog>
<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>×</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>
<div id="discoveryNamesList" class="discovery-name-list"></div>
<div class="form-actions"><button type="button" class="secondary" data-close
data-i18n="actions.later">Later</button><button class="primary" type="submit"
data-i18n="actions.save">Save</button></div>
</form>
</dialog>
<dialog id="renameDeviceDialog">
<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>×</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>
<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>
<div id="deviceConfigCheckResult" class="inline-alert" 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"
data-i18n="actions.save">Save</button><button class="primary" type="submit" data-save-mode="check"
data-i18n="devices.saveAndCheck">Save and check connection</button></div>
</form>
</dialog>
<dialog id="deviceDetailsDialog" class="dialog-wide">
<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>
<button type="button" data-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="settings-block">
<div class="settings-block-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="settings-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>
<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>
</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>×</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="settings-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>
<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>
</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>×</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>
</dialog>
<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>
<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>
<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>
</div>
<div class="ping-live-grid" id="pingLiveGrid"></div>
</div>
</dialog>
<dialog id="zoneDialog">
<form method="dialog" id="zoneForm" class="dialog-form">
<input type="hidden" name="id">
<div class="dialog-head">
<h2 data-i18n="common.zone">Zone</h2><button type="button" data-close>×</button>
</div>
<label><span data-i18n="common.name">Name</span><input name="name" required
data-i18n-placeholder="placeholder.livingRoom" placeholder="Living room"></label>
<label><span data-i18n="common.device">Device</span><select name="device_id" required></select></label>
<div class="copy-settings-row"><select id="copyZoneSource">
<option value="" data-i18n="zones.copyFrom">Copy thermostat settings from…</option>
</select><button type="button" class="secondary" id="copyZoneSettings" data-i18n="zones.copySettings">Copy
settings</button></div>
<label><span data-i18n="zones.modePolicy">Mode policy</span><select name="mode_policy">
<option value="house" data-i18n="zones.followHouse">Follow global mode</option>
<option value="cool" data-i18n="zones.coolOnly">Cooling only</option>
<option value="heat" data-i18n="zones.heatOnly">Heating only</option>
</select></label><input type="hidden" name="setpoint" value="23">
<p class="field-note" data-i18n="zones.modePolicyHint">If this zone should use the global Heating/Cooling mode
selected in GREE Controller, leave “Follow global mode” unchanged. Cooling only / Heating only forces a fixed
mode for this zone.</p>
<details class="profile-editor">
<summary data-i18n="zones.profileTemperatures">Comfort / sleep / away temperatures</summary>
<div class="profile-grid"><strong data-i18n="mode.cool">Cooling</strong><label><span
data-i18n="preset.comfort">Comfort</span><input type="text" inputmode="decimal" step="0.1"
name="cool_comfort_setpoint" value="23"></label><label><span data-i18n="preset.sleep">Sleep</span><input
type="text" inputmode="decimal" step="0.1" name="cool_sleep_setpoint" value="24.5"></label><label><span
data-i18n="preset.away">Away</span><input type="text" inputmode="decimal" step="0.1"
name="cool_away_setpoint" value="27"></label></div>
<div class="profile-grid"><strong data-i18n="mode.heat">Heating</strong><label><span
data-i18n="preset.comfort">Comfort</span><input type="text" inputmode="decimal" step="0.1"
name="heat_comfort_setpoint" value="21"></label><label><span data-i18n="preset.sleep">Sleep</span><input
type="text" inputmode="decimal" step="0.1" name="heat_sleep_setpoint" value="19"></label><label><span
data-i18n="preset.away">Away</span><input type="text" inputmode="decimal" step="0.1"
name="heat_away_setpoint" value="17"></label></div>
</details>
<div class="two zone-hysteresis-row">
<div class="hysteresis-config"><label id="commonHysteresisField"><span data-i18n="zones.hysteresis">Hysteresis
°C</span><input type="text" inputmode="decimal" step="0.1" min="0.1" max="5" name="hysteresis"
value="0.6"></label><label class="check" data-i18n-title="zones.separateHysteresisHint"
title="Use different hysteresis values for heating and cooling"><input type="checkbox"
name="separate_hysteresis"> <span data-i18n="zones.separateHysteresis">Set heating and cooling hysteresis
separately</span></label></div><label><span data-i18n="zones.source">Temperature strategy</span><select
name="sensor_source">
<option value="combined" selected data-i18n="zones.combinedSensor">GREE + room sensor</option>
<option value="device" data-i18n="zones.greeSensor">GREE only</option>
<option value="home_assistant" data-i18n="zones.externalSensor">Room sensor only</option>
</select></label>
</div>
<div id="separateHysteresisFields" class="two" hidden><label><span data-i18n="zones.coolHysteresis">Cooling
hysteresis °C</span><input type="text" inputmode="decimal" step="0.1" min="0.1" max="5"
name="cool_hysteresis" value="0.6"></label><label><span data-i18n="zones.heatHysteresis">Heating hysteresis
°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"
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">The room sensor is assigned only to this zone. If it becomes
unavailable, the controller falls back to the GREE sensor.</p>
</div>
<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"
step="0.5" min="0.5" max="8" name="standby_offset_c" value="2"></label></div>
<label class="check"><input type="checkbox" name="smart_fan" checked> <span data-i18n="zones.smartFan">Smart fan
assist</span></label>
<input type="hidden" name="min_on_seconds" value="180"><input type="hidden" name="min_off_seconds"
value="180"><input type="hidden" name="sensor_stale_after_seconds" value="300"><input type="hidden"
name="revision" value="">
<label class="check"><input type="checkbox" name="enabled" checked> <span
data-i18n="common.enabled">Enabled</span></label>
<p class="field-note" data-i18n="zones.enabledAutomationDescription">Disabling the zone stops automation. Manual
thermostat, temporary thermostat and direct manual control remain available.</p>
<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="compressorQueueDialog" class="compressor-queue-dialog">
<div class="dialog-form compressor-queue-dialog-body">
<div class="dialog-head">
<div><span class="eyebrow" data-i18n="zones.queueEyebrow">Compressor protection</span>
<h2 data-i18n="zones.queueTitle">Command queue</h2>
</div><button type="button" data-close>×</button>
</div>
<p class="field-note" data-i18n="zones.queueHint">Commands waiting for the compressor protection window to end.
You can cancel one task or clear the whole queue.</p>
<div class="compressor-queue-summary"><span data-i18n="zones.queuePendingLabel">Waiting</span><strong
id="compressorQueueModalCount">0</strong></div>
<div id="compressorQueueList" class="compressor-queue-list"></div>
<div class="form-actions compressor-queue-actions"><button type="button" class="danger"
id="compressorQueueCancelAll" data-action="cancel-all-compressor-tasks"
data-i18n="zones.cancelAllQueued">Cancel all waiting</button><button type="button" class="primary" data-close
data-i18n="actions.done">Done</button></div>
</div>
</dialog>
<dialog id="temporaryThermostatDialog">
<form method="dialog" id="temporaryThermostatForm" class="dialog-form temporary-thermostat-form">
<input type="hidden" name="zone_id">
<div class="dialog-head">
<div><span class="eyebrow" data-i18n="zones.quickThermostat">Szybki termostat</span>
<h2 data-i18n="zones.temporaryTitle">Włącz czasowo</h2>
</div><button type="button" data-close>×</button>
</div>
<div id="temporaryThermostatActive" class="temporary-active-summary" hidden>
<div><small id="temporaryThermostatActiveLabel" data-i18n="zones.temporaryActive">Aktywny tryb
czasowy</small><strong id="temporaryThermostatActiveCountdown"></strong><span
id="temporaryThermostatActiveDetail"></span></div>
<button type="button" class="danger" id="temporaryThermostatStop" data-i18n="zones.temporaryStop">Zakończ
teraz</button>
</div>
<label><span data-i18n="zones.temporaryTarget">Temperatura szybkiego termostatu</span><input type="text"
inputmode="decimal" name="target_temperature" min="8" max="30" step="0.1" required></label>
<label><span data-i18n="zones.temporaryStartRule">Kiedy uruchomić</span><select name="start_kind"
id="temporaryStartKind">
<option value="now" data-i18n="zones.temporaryStartNow">Od razu</option>
<option value="delay" data-i18n="zones.temporaryStartDelay">Z opóźnieniem</option>
<option value="at" data-i18n="zones.temporaryStartAt">O konkretnej dacie i godzinie</option>
</select></label>
<div id="temporaryStartDelayFields" class="temporary-rule-fields" hidden>
<label><span data-i18n="zones.temporaryStartDelayMinutes">Uruchom za (min)</span><input type="number"
name="start_delay_minutes" min="1" max="43200" value="30"></label>
<div class="temporary-presets"><button type="button" data-temporary-start-delay="15">15 min</button><button
type="button" data-temporary-start-delay="30">30 min</button><button type="button"
data-temporary-start-delay="60">1 h</button><button type="button" data-temporary-start-delay="120">2
h</button></div>
</div>
<div id="temporaryStartAtFields" class="temporary-rule-fields" hidden>
<label><span data-i18n="zones.temporaryStartAtDate">Uruchom o</span><input type="datetime-local"
name="start_at"></label>
</div>
<label><span data-i18n="zones.temporaryFinishRule">Kiedy wrócić do automatyki</span><select name="finish_kind"
id="temporaryFinishKind">
<option value="duration" data-i18n="zones.temporaryDuration">Po określonym czasie</option>
<option value="until" data-i18n="zones.temporaryUntil">O konkretnej dacie i godzinie</option>
<option value="temperature_reached" data-i18n="zones.temporaryReached">Po osiągnięciu warunku temperatury
</option>
<option value="temperature_stable" data-i18n="zones.temporaryStable">Po utrzymaniu warunku temperatury
</option>
<option value="schedule_boundary" data-i18n="zones.temporaryScheduleBoundary">Przy następnym przejściu
harmonogramu</option>
</select></label>
<div id="temporaryDurationFields" class="temporary-rule-fields">
<label><span data-i18n="zones.temporaryDurationMinutes">Czas działania (min)</span><input type="number"
name="duration_minutes" min="1" max="14400" value="60"></label>
<div class="temporary-presets"><button type="button" data-temporary-duration="30">30 min</button><button
type="button" data-temporary-duration="60">1 h</button><button type="button" data-temporary-duration="120">2
h</button><button type="button" data-temporary-duration="240">4 h</button></div>
</div>
<div id="temporaryUntilFields" class="temporary-rule-fields" hidden>
<label><span data-i18n="zones.temporaryUntilDate">Wyłącz o</span><input type="datetime-local"
name="until"></label>
</div>
<div id="temporaryTemperatureFields" class="temporary-rule-fields" hidden>
<div class="two"><label><span data-i18n="zones.temporaryCondition">Warunek</span><select
name="temperature_operator">
<option value="within" data-i18n="zones.temporaryWithin">w zakresie celu ± tolerancja</option>
<option value="at_or_below" data-i18n="zones.temporaryAtOrBelow">temperatura ≤ cel</option>
<option value="at_or_above" data-i18n="zones.temporaryAtOrAbove">temperatura ≥ cel</option>
</select></label><label><span data-i18n="zones.temporaryTolerance">Tolerancja °C</span><input type="number"
name="tolerance_c" min="0.1" max="3" step="0.1" value="0.3"></label></div>
<label id="temporaryHoldField"><span data-i18n="zones.temporaryHoldMinutes">Warunek musi trwać
(min)</span><input type="number" name="hold_minutes" min="1" max="1440" value="60"></label>
<label><span data-i18n="zones.temporarySafetyLimit">Limit bezpieczeństwa (min, opcjonalnie)</span><input
type="number" name="max_duration_minutes" min="1" max="14400" value="240"></label>
<p class="field-note" data-i18n="zones.temporaryStableHint">Jeśli temperatura wyjdzie poza warunek, licznik
utrzymania zeruje się i zaczyna od nowa po ponownym wejściu w zakres.</p>
</div>
<div id="temporaryScheduleFields" class="temporary-rule-fields" hidden>
<p class="field-note" data-i18n="zones.temporaryScheduleHint">Szybki termostat zakończy się przy najbliższej
zmianie aktywnego wpisu harmonogramu tej strefy.</p>
</div>
<div class="form-actions"><button type="button" class="secondary" data-close
data-i18n="actions.cancel">Anuluj</button><button class="primary" type="submit" id="temporaryThermostatSubmit"
data-i18n="zones.temporaryStart">Włącz czasowo</button></div>
</form>
</dialog>
<dialog id="groupDialog">
<form method="dialog" id="groupForm" class="dialog-form">
<input type="hidden" name="id">
<div class="dialog-head">
<h2 data-i18n="groups.group">Group</h2><button type="button" data-close>×</button>
</div>
<label><span data-i18n="common.name">Name</span><input name="name" required
data-i18n-placeholder="groups.namePlaceholder" placeholder="Upstairs"></label>
<fieldset>
<legend data-i18n="groups.members">Group members</legend>
<div class="group-zone-choices" id="groupZoneChoices"></div>
</fieldset>
<p class="field-note" data-i18n="groups.membersHint">Groups are built from thermostat zones. ON takes control of
members; OFF powers their units down without leaving a group ownership lock.</p>
<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="scheduleDialog">
<form method="dialog" id="scheduleForm" class="dialog-form">
<input type="hidden" name="id">
<div class="dialog-head">
<h2 data-i18n="common.schedule">Schedule</h2><button type="button" data-close>×</button>
</div>
<label><span data-i18n="common.name">Name</span><input name="name" required
data-i18n-placeholder="placeholder.night" placeholder="Night"></label>
<label><span data-i18n="common.zone">Zone</span><select name="zone_id" required></select></label>
<fieldset>
<legend data-i18n="schedules.weekdays">Weekdays</legend>
<div class="days"><label><input type="checkbox" name="weekday" value="1" checked><span
data-day="1">Mon</span></label><label><input type="checkbox" name="weekday" value="2" checked><span
data-day="2">Tue</span></label><label><input type="checkbox" name="weekday" value="3" checked><span
data-day="3">Wed</span></label><label><input type="checkbox" name="weekday" value="4" checked><span
data-day="4">Thu</span></label><label><input type="checkbox" name="weekday" value="5" checked><span
data-day="5">Fri</span></label><label><input type="checkbox" name="weekday" value="6"><span
data-day="6">Sat</span></label><label><input type="checkbox" name="weekday" value="7"><span
data-day="7">Sun</span></label></div>
</fieldset>
<div class="two"><label><span data-i18n="common.from">From</span><input type="time" name="start_time"
value="22:00" required></label><label><span data-i18n="common.to">To</span><input type="time"
name="end_time" value="06:00" required></label></div>
<label><span data-i18n="schedules.profile">Profile</span><select name="preset">
<option value="comfort" data-i18n="preset.comfort">Comfort</option>
<option value="sleep" data-i18n="preset.sleep">Sleep</option>
<option value="away" data-i18n="preset.away">Away</option>
<option value="custom" data-i18n="preset.custom">Custom temperature</option>
</select></label>
<label id="scheduleSetpointField"><span data-i18n="common.temperatureC">Custom temperature °C</span><input
type="text" inputmode="decimal" name="setpoint" step="0.1" min="8" max="30" value="23"></label>
<label class="check"><input type="checkbox" name="enabled" checked> <span
data-i18n="common.enabled">Enabled</span></label>
<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="automationDialog">
<form method="dialog" id="automationForm" class="dialog-form">
<input type="hidden" name="id">
<div class="dialog-head">
<h2 data-i18n="common.automation">Automation</h2><button type="button" data-close>×</button>
</div>
<div class="copy-settings-row"><select id="automationPreset">
<option value="" data-i18n="automations.preset">Preset…</option>
<option value="hot" data-i18n="automations.presetHot">High temperature cooling</option>
<option value="cold" data-i18n="automations.presetCold">Low temperature heating</option>
<option value="morning" data-i18n="automations.presetMorning">Morning comfort</option>
<option value="nightoff" data-i18n="automations.presetNightOff">Night power off</option>
</select><button type="button" class="secondary" id="applyAutomationPreset"
data-i18n="actions.apply">Apply</button></div>
<label><span data-i18n="common.name">Name</span><input name="name" required
data-i18n-placeholder="automations.namePlaceholder" placeholder="Emergency cooling"></label>
<label><span data-i18n="automations.trigger">Trigger</span><select name="trigger_kind">
<option value="temperature_above" data-i18n="automations.tempAbove">Temperature above</option>
<option value="temperature_below" data-i18n="automations.tempBelow">Temperature below</option>
<option value="time" data-i18n="automations.time">Time</option>
</select></label>
<label><span data-i18n="automations.measurementDevice">Measurement device</span><select
name="trigger_device_id"></select></label>
<div class="two"><label><span data-i18n="automations.thresholdC">Threshold °C</span><input type="text"
inputmode="decimal" step="0.1" name="threshold" value="27"></label><label><span
data-i18n="automations.time">Time</span><input type="time" name="at_time" value="08:00"></label></div>
<hr>
<h3 data-i18n="automations.action">Action</h3>
<label><span data-i18n="automations.targetType">Target type</span><select name="action_target_kind">
<option value="device" data-i18n="common.device">Device</option>
<option value="group" data-i18n="groups.group">Group</option>
</select></label>
<label id="automationDeviceTarget"><span data-i18n="common.device">Device</span><select
name="action_device_id"></select></label>
<label id="automationGroupTarget" hidden><span data-i18n="groups.group">Group</span><select
name="action_group_id"></select></label>
<div class="two"><label><span data-i18n="common.power">Power</span><select name="action_power">
<option value="" data-i18n="actions.noChange">No change</option>
<option value="true" data-i18n="actions.turnOn">Turn on</option>
<option value="false" data-i18n="actions.turnOff">Turn off</option>
</select></label><label><span data-i18n="common.mode">Mode</span><select name="action_mode">
<option value="" data-i18n="actions.noChange">No change</option>
<option value="cool" data-i18n="mode.cool">Cooling</option>
<option value="heat" data-i18n="mode.heat">Heating</option>
<option value="dry" data-i18n="mode.dry">Dry</option>
<option value="fan" data-i18n="mode.fan">Fan</option>
<option value="auto" data-i18n="mode.auto">Auto</option>
</select></label></div>
<label id="automationGroupPreset" hidden><span data-i18n="groups.profile">Group profile</span><select
name="action_preset">
<option value="" data-i18n="actions.noChange">No change</option>
<option value="auto" data-i18n="preset.auto">Auto</option>
<option value="comfort" data-i18n="preset.comfort">Comfort</option>
<option value="sleep" data-i18n="preset.sleep">Sleep</option>
<option value="away" data-i18n="preset.away">Away</option>
</select></label>
<div class="two"><label id="automationTargetTemperature"><span data-i18n="common.targetC">Target °C</span><input
type="text" inputmode="decimal" step="0.1" min="8" max="30"
name="action_target_temperature"></label><label><span data-i18n="common.cooldownSeconds">Cooldown
(s)</span><input type="number" min="30" name="cooldown_seconds" value="300"></label></div>
<div class="two" id="automationDeviceSwingOptions">
<label><span data-i18n="devices.swingVertical">Vertical swing</span><select name="action_swing_vertical">
<option value="" data-i18n="actions.noChange">No change</option>
<option value="true" data-i18n="actions.turnOn">Turn on</option>
<option value="false" data-i18n="actions.turnOff">Turn off</option>
</select></label>
<label><span data-i18n="devices.swingHorizontal">Horizontal swing</span><select name="action_swing_horizontal">
<option value="" data-i18n="actions.noChange">No change</option>
<option value="true" data-i18n="actions.turnOn">Turn on</option>
<option value="false" data-i18n="actions.turnOff">Turn off</option>
</select></label>
</div>
<p class="field-note" id="automationGroupHint" hidden data-i18n="automations.groupHint">For a group, Auto mode
means follow the whole-house heating/cooling mode. Group presets are applied to all member zones.</p>
<label class="check"><input type="checkbox" name="enabled" checked> <span
data-i18n="common.enabled">Enabled</span></label>
<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="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>×</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"
readonly></label>
<div class="form-actions"><button type="button" class="secondary" id="copyAccessToken"
data-i18n="actions.copy">Copy</button><button type="button" class="primary" data-close
data-i18n="actions.done">Done</button></div>
</div>
</dialog>
<dialog id="tokenDialog" class="auth-dialog">
<form method="dialog" id="tokenForm" class="dialog-form">
<div class="brand large">
<div><strong>GREE Controller</strong><small data-i18n="auth.required">Authentication required</small></div>
</div>
<label><span data-i18n="auth.token">Access token</span><input type="password" name="token" required
autocomplete="current-password"></label>
<button class="primary" type="submit" data-i18n="auth.connect">Connect</button>
</form>
</dialog>
<aside id="debugOverlay" class="debug-overlay" hidden>
<div class="debug-overlay-head">
<div class="debug-overlay-title"><strong data-i18n="debug.title">Live debug</strong><small
id="debugOverlayStatus"></small></div>
<div class="debug-overlay-actions">
<div class="debug-source-tabs" role="tablist" data-i18n-aria="debug.filterAria" aria-label="Debug source">
<button type="button" class="active" role="tab" aria-selected="true" data-debug-filter="all"
data-i18n="debug.all">All</button>
<button type="button" role="tab" aria-selected="false" data-debug-filter="requests"
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="mqtt"
data-i18n="debug.mqtt">MQTT</button>
</div>
<button type="button" class="debug-clear" data-action="debug-clear" data-i18n="debug.clear">Clear</button>
</div>
</div>
<div id="debugOverlayLines" class="debug-overlay-lines"></div>
</aside>
<div id="toastStack" class="toast-stack" role="status" aria-live="polite" aria-atomic="false"></div>
<script src="__GREE_APP_ASSET__" defer></script>
</body>
</html>