Bring native AC control into the Shelly Smart Control app — powered by Home Assistant as an invisible local bridge.
Current Release: v1.1 | Target: Any Shelly Gen3 or Gen4 with virtual component support
📁 Note: Emoji rendering may vary between Android, iOS, and desktop — the glyphs are functionally identical across platforms.
Climate Bridge turns any compatible Shelly device into a native AC control panel inside the Shelly Smart Control app. Home Assistant acts as a silent local bridge to any HA climate entity — providing bidirectional sync between Shelly virtual components and your AC unit.
The Shelly app is the UI. Home Assistant is invisible infrastructure. No cloud. No proprietary AC app. No third-party dashboards.
Once installed, your AC appears in the Shelly ecosystem as a full virtual device — controllable via the Shelly app, Shelly Scenes, Schedules, and Local Automations just like any native Shelly device.
Most AC units have no native presence in the Shelly ecosystem. Users cannot control their AC via the Shelly app, Shelly Scenes, or Shelly Schedules. From the Shelly side, the AC is completely invisible.
Climate Bridge fixes this by creating Shelly Virtual Components that represent the AC unit directly — with full bidirectional sync to HA on the local network.
Shelly App (user)
│
▼
Virtual Components (enum / number / boolean)
│
├── User changes mode / temp / fan / swing
│ → Brain debounces 800ms
│ → HTTP POST to HA climate service
│ → AC unit responds
│
└── HA pushes state on every climate entity change
→ Brain receives POST on /script/{id}/sync
→ Brain updates all Virtual Components
→ Sync lock (1.5s) prevents echo loop
→ Status text refreshed with health glyph
Climate Bridge is 100% local. All communication is Shelly ↔ Home Assistant over your local network — no cloud services are involved in the bridge layer. The cloudless nature of your AC unit's underlying HA integration (e.g. Broadlink, Daikin, Mitsubishi) depends on that integration — Climate Bridge does not change or influence it.
| Component | Role |
|---|---|
| Any Shelly Gen3 or Gen4 device | Hosts the scripts and virtual components. No relay, metering, or physical I/O is used or required. |
| Home Assistant instance (local) | Acts as the bridge. Must be reachable from the Shelly device over LAN. |
Any HA climate entity |
The AC unit already integrated into HA. Climate Bridge is integration-agnostic. |
| Shelly BLU H&T (optional) | Adds live room temperature and humidity to the virtual device card via BTHome. |
Host device examples: Shelly Gen4 Mini 1PM on a room light, Plus Plug S, Plus 1, Pro 4PM. The host device's physical function is completely independent — Climate Bridge does not interfere with it.
⚠️ Important: Home Assistant must be able to reach the Shelly device's IP address over your local network. Devices on separate VLANs or subnets require appropriate routing.
- Bidirectional sync — Changes from the Shelly app reach HA instantly. Changes in HA (schedules, scripts, voice, other automations) reflect in the Shelly app automatically.
- Fully local — The Climate Bridge layer communicates exclusively over your LAN. Zero cloud dependency within the bridge itself.
- Integration-agnostic — Works with any HA
climateentity regardless of underlying integration or AC brand. - Any Shelly host — Runs on any Gen3/Gen4 device. Shares the host cleanly without touching physical I/O.
- Configurable capabilities — Match your AC exactly: choose modes, fan speeds, swing options. Remove what your AC doesn't support.
- Optional BTHome room sensor — Pair a Shelly BLU H&T to display live room temperature and humidity on the same virtual device card.
- Power toggle — Optional quick-access boolean toggle for on/off. Coexists with the mode dropdown — does not replace it.
- Compact status display — Single-line status text with mode, fan, swing, temperature, and HA health glyph in 50 characters.
- Passive health tracking — Status glyph reflects HA connectivity. No active polling — zero overhead.
- Reboot recovery — Cached state in Script.storage restores the last known AC state after a device reboot.
- Echo prevention — Sync lock and last-value deduplication suppress feedback loops between Shelly and HA.
- Preflight protection — Setup refuses to run if SITE_CONFIG still contains placeholder values, or if components are already installed.
- Unified Setup script — Single script handles install, reconfigure, and cleanup via independent operation toggles. No separate Installer and Cleanup scripts.
| # | Component | ID | Type | Direction | Condition |
|---|---|---|---|---|---|
| 1 | State | text:200 |
Virtual Text | Brain writes | Always |
| 2 | Target Temp | number:200 |
Virtual Number | Shelly ↔ HA | Always |
| 3 | AC Mode | enum:200 |
Virtual Enum | Shelly ↔ HA | Always |
| 4 | Fan Speed | enum:201 |
Virtual Enum | Shelly ↔ HA | Always |
| 5 | Swing | enum:202 |
Virtual Enum | Shelly ↔ HA | swing_modes not empty |
| 6 | Room Temp | bthomesensor:{id} |
BTHome | Native BTHome | has_bthome: true |
| 7 | Room Humidity | bthomesensor:{id} |
BTHome | Native BTHome | has_bthome: true |
| 6* | Room Temp | number:201 |
Virtual Number | HA → Shelly | has_bthome: false |
| 7* | Room Humidity | number:202 |
Virtual Number | HA → Shelly | has_bthome: false |
| 8 | Power | boolean:200 |
Virtual Boolean | Shelly ↔ HA | add_power_toggle: true |
| — | Group | group:200 |
Virtual Group | Contains all | Always |
AC Mode (enum:200) always includes "Off" as an option — this maps directly to HA's hvac_mode: off. The optional Power toggle (boolean:200) is a supplementary quick-access control — it does not replace "Off" in the mode dropdown. Both coexist independently.
Shelly devices support a maximum of 10 virtual components. Climate Bridge uses between 6 and 10 slots depending on your configuration — leaving little or no room for other scripts sharing the same device. It is strongly recommended to host Climate Bridge on a dedicated device that is not already using virtual components — a Plus Plug S, Plus 1, or Gen4 Mini are all suitable.
⚠️ add warning using a device with existing components and script is not advise. If your host device already has virtual components from another script, count your available slots before running the Setup script. The Setup script will abort cleanly if the component limit is reached during creation.
The status line is a compact glyph string — max 50 characters, confirmed on hardware. Raw UTF-8 characters only. It is designed to display cleanly in the small parameter slot of a Shelly dashboard card, giving a full AC state summary in a single line without truncation.
🔥22°|֎H|🏠19° 75%|📶 Heat, High fan, room 19°/75%, HA healthy
❄️24°|֎A|↕️|🏠21° 60%|📶 Cool, Auto fan, Swing Vertical, room data, healthy
⏸️Off|🏠20° 55%|📶 Off, room data, HA healthy
🔥22°|֎M|🏠19° 75%|⚠️ Heat, Medium fan, room data, HA warning
⏸️Off|❌ Off, HA unreachable
Mode glyphs: ❄️ Cool · 🔥 Heat · 💨 Fan · 💧 Dry · 🔁 Auto · ⏸️ Off
Fan glyphs: ֎A Auto · ֎L Low · ֎M Medium · ֎H High
Swing glyphs:
Room data prefix: 🏠 (precedes room temperature and humidity when present)
Health glyphs: 📶 Healthy ·
Health resets to 📶 automatically on any successful HA call or inbound push received.
📱 Device note: Some emoji render differently on Android compared to iOS or desktop. The glyphs are functionally identical — only the visual style varies by platform and OS version.
Extract group:200 as a Virtual Device (Shelly Premium feature) for the best card experience.
All components in the group can be added, removed, and reordered freely in the Shelly app card customisation screen. The layout below is a suggested starting point that works well for day-to-day use — it is not a requirement.
Suggested layout:
- Big parameter: Power (boolean toggle — quick on/off)
- Small parameters: State (text:200 — full status in one line)
The State component (text:200) is specifically designed to fit the small parameter slot: it shows mode, temperature, fan speed, swing, and HA health in a single compact line. Assign and order any parameters that suit your workflow.
| Script | Purpose | Run on boot |
|---|---|---|
ClimateBridge_Setup_v1.0.js |
Commissioning, reconfiguration, and cleanup. Four independent operation toggles — run any combination. Self-stops on completion. | No — run as needed |
ClimateBridge_Brain_v1.1.js |
Runtime engine. Bidirectional sync, status, health tracking. | Yes — always |
ClimateBridge_Showcase_v2.1.js |
UI demo tool. Cycles through all AC states automatically, then enters manual mode for interactive dropdown testing. Run before going live to verify the UI looks correct. Stop and delete after use. | No — demo only |
⚠️ Setup replaces both the Installer and Cleanup scripts from v1.0. If you are upgrading from v1.0, the Setup script handles both fresh installs and reconfiguration. The separateInstallerandCleanupscripts are retired.
Set the toggles at the top of ClimateBridge_Setup_v1.0.js before running. All default to false — set only what you need.
| Toggle | What it does |
|---|---|
DELETE_VCS |
Removes all Climate Bridge virtual components from the device. BTHome sensors and scripts are never touched. |
DELETE_KVS |
Removes all bridge_ KVS keys. Usually not needed — SET_KVS always overwrites. |
SET_KVS |
Writes all bridge_ KVS keys from SITE_CONFIG. Always run this for a new install or config change. |
CREATE_VCS |
Creates and configures all virtual components. Run alongside SET_KVS for a fresh install. |
Fresh install: SET_KVS=true + CREATE_VCS=true
Reconfigure (KVS only — no VC changes): SET_KVS=true
Full reinstall (wipe and rebuild): DELETE_VCS=true + SET_KVS=true + CREATE_VCS=true
- Any Shelly Gen3 or Gen4 device with virtual component support (firmware 1.4.4 or later recommended)
- A running Home Assistant instance reachable from the Shelly device on your local network
- A
climateentity already configured and working in Home Assistant - A Long-Lived Access Token from your HA profile page
- (Optional) A paired Shelly BLU H&T sensor if you want live room temperature and humidity from a local sensor. If you do not have one, Climate Bridge can display room temperature and humidity sourced from your AC unit's HA integration instead — set
has_bthome: falseinSITE_CONFIG.
⚠️ Reinstalling or changing configuration? UseClimateBridge_Setup_v1.0.jswithDELETE_VCS=trueto remove existing components before creating new ones. The Setup script will abort if it detects components already installed andDELETE_VCSisfalse.
⚠️ Security — HA Long-Lived Access Token: Your HA token is stored in the Shelly device's KVS under the keybridge_auth. It is not transmitted externally — it is used only for local HTTP calls from the Shelly device to your HA instance. Treat it with the same care as any credential: do not paste it into shared scripts, community forum posts, or public repositories.To update a token: you can either re-run the Setup script with
SET_KVS=trueand the new token inSITE_CONFIG, or edit thebridge_authKVS key directly in the Shelly web UI (Scripts → KVS) and restart the Brain. Editingbridge_authalone is safe. Be cautious when editing any otherbridge_KVS keys directly — the Brain reads its entire configuration from KVS on boot, and incorrect values can break sync silently. If in doubt, re-run Setup from scratch.
⚡ Electrical safety: Shelly devices interface with mains-powered electrical installations. If you are not qualified to work with mains wiring, engage a licensed electrician. Incorrect installation is dangerous. Climate Bridge itself runs on the host device's scripting engine and does not modify wiring — but the host device must be installed safely before any scripting work begins.
This phase prepares HA to push state to Climate Bridge on every change.
💡 Finding your SCRIPT_ID: The Brain prints the full sync endpoint URL on every boot — you do not need to look it up manually. Check the Shelly console after starting the Brain:
[CB] sync endpoint: http://192.168.x.x/script/1/syncThe number after
/script/is yourSCRIPT_ID. Use this URL in your HArest_command.If you also set
print_yaml: trueinSITE_CONFIG, the Brain will print additional config details to the console on boot. Note that the Shelly console prepends a timestamp to every log line — the output cannot be pasted directly into HA. Use theClimateBridge_HA_Config.yamlfile provided in the repository and fill in your values manually.
Step 1 — Add the rest_command
Add the following to your configuration.yaml. Choose the variant that matches your setup.
Which variant do I use?
The difference is in room temperature and humidity — not in how the AC is controlled.
- Variant A (
has_bthome: false— default) — Room temperature and humidity come from your AC unit's HA integration. The Brain writes these to virtual number components from the HA push payload. This is the default variant. - Variant B (
has_bthome: true) — You have a paired Shelly BLU H&T sensor. Room data is displayed via native BTHome — the Brain is not involved. Removecurrent_tempandhumidityfrom the payload to avoid JSON errors if your AC does not report those attributes.
Variant A — Standard (has_bthome: false)
rest_command:
sync_climate_bridge:
url: "http://SHELLY_IP/script/SCRIPT_ID/sync"
method: POST
content_type: 'application/json'
payload: >
{% set e = 'ENTITY_ID' %}
{
"temp": {{ state_attr(e, 'temperature') | default(21) }},
"hvac": "{{ states(e) | default('off') }}",
"fan": "{{ state_attr(e, 'fan_mode') | default('auto') }}",
"swing": "{{ state_attr(e, 'swing_mode') | default('off') }}",
"current_temp": {{ state_attr(e, 'current_temperature') | int(0) }},
"humidity": {{ state_attr(e, 'humidity') | int(0) }}
}Variant B — With BTHome sensor (has_bthome: true)
rest_command:
sync_climate_bridge:
url: "http://SHELLY_IP/script/SCRIPT_ID/sync"
method: POST
content_type: 'application/json'
payload: >
{% set e = 'ENTITY_ID' %}
{
"temp": {{ state_attr(e, 'temperature') | default(21) }},
"hvac": "{{ states(e) | default('off') }}",
"fan": "{{ state_attr(e, 'fan_mode') | default('auto') }}",
"swing": "{{ state_attr(e, 'swing_mode') | default('off') }}"
}
⚠️ Use| int(0)for numeric attributes — not| default(). Jinja2's| default()filter does NOT catch PythonNonefromstate_attr— it only catches undefined variables. If your AC does not reportcurrent_temperatureorhumidity, those attributes returnNone, which passes through| default()unchanged and renders as the literal stringNonein the JSON payload, breaking the push silently. The| int(0)filter correctly convertsNoneto0. The Brain suppresses0humidity from the status display — it is safe to leave in the payload even if your AC never reports humidity.
💡 Verify your payload before restarting HA. Go to HA Developer Tools → Template and paste the payload block. All values should resolve to numbers or quoted strings. If you see
Noneanywhere, your AC integration does not report that attribute — use| int(0)as shown above.
Replace the placeholders:
SHELLY_IP→ your Shelly device's IP addressSCRIPT_ID→ the Brain script slot number (printed in full on boot:[CB] sync endpoint: http://IP/script/N/sync)ENTITY_ID→ your HA climate entity e.g.climate.bedroom_ac
Step 2 — Add the automation
Add the following to your automations.yaml:
- alias: Push AC to Climate Bridge
description: "Push AC state to Shelly on every state or attribute change"
triggers:
- entity_id: ENTITY_ID
trigger: state
actions:
- action: rest_command.sync_climate_bridge
mode: queued
max_exceeded: silentmode: queued ensures every state change is processed in order — no changes are dropped under rapid updates. max_exceeded: silent suppresses the HA warning log when the queue fills during rapid changes.
Step 3 — Restart Home Assistant
rest_command is defined in configuration.yaml and requires a full HA restart — not a partial reload.
Settings → System → Restart Home Assistant
Step 4 — Verify the push is working
Before running the Setup script, confirm HA can reach the Shelly device:
Developer Tools → Actions → rest_command.sync_climate_bridge → Call Action
You should see activity in the Shelly script console. If no push arrives, check:
- HA can ping the Shelly IP (cross-subnet routing if needed)
- The
SCRIPT_IDplaceholder has been replaced with the actual script number - The automation shows a recent "Last triggered" timestamp
Step 1 — Create a new script on your Shelly device named ClimateBridge_Setup.
Step 2 — Paste the contents of ClimateBridge_Setup_v1.0.js.
Step 3 — Set the operation toggles at the top of the script. For a fresh install:
const DELETE_VCS = false;
const DELETE_KVS = false;
const SET_KVS = true;
const CREATE_VCS = true;Step 4 — Edit SITE_CONFIG. This is the only section you edit. See the full SITE_CONFIG Reference below.
Key items to fill in:
ha_token— your HA Long-Lived Access Tokenha_url— your HA URL e.g.http://192.168.1.X:8123entity_id— yourclimateentity e.g.climate.bedroom_acdevice_name— display name for the virtual device e.g.Bedroom ACmodes,fan_speeds,swing_modes— match your AC's actual capabilities exactly
Optional features — enable or disable to match your setup:
| Flag | What it does | Default |
|---|---|---|
has_bthome |
true — Setup adds your existing paired BLU H&T sensor components to the group. Room temp and humidity display natively, Brain is not involved. false — Brain writes room temp and humidity from HA push data into virtual number components instead. |
false |
add_swing |
true — creates the Swing virtual component (enum:202) and enables swing sync. false — no swing component created, swing is ignored entirely. Set to false if your AC has no swing control. |
true |
add_power_toggle |
true — creates a boolean Power toggle (boolean:200) for quick on/off. false — no toggle created. The mode dropdown always includes "Off" regardless of this setting. |
true |
add_room_humidity |
true — creates a Room Humidity virtual component (number:202). Set to false if your AC does not report humidity and you do not want an empty component in the group. Only applies when has_bthome: false. |
true |
⚠️ Match your HA entity exactly. Open your climate entity in HA Developer Tools → States and check the availablehvac_modesandfan_modesattributes. Only include modes your AC actually supports.
⚠️ HA usesfan_only— Climate Bridge showsFan. HA's internal name for fan-only mode isfan_only. Climate Bridge maps this automatically. InSITE_CONFIG.modesyou write'Fan'— the Setup script generates the correct mapping.
Step 5 — Run the Setup script. Watch the console. You will see each phase logged as it completes. The script runs through four phases with generous settling pauses between them — allow approximately 90 seconds for a full install.
The Setup script self-stops on completion. You do not need to manually stop it.
Step 6 — Refresh the Shelly app. The new virtual device components should appear.
Step 1 — Create a new script named ClimateBridge_Brain.
Step 2 — Paste the contents of ClimateBridge_Brain_v1.1.js.
Step 3 — Do not edit the Brain. All configuration was written to KVS by the Setup script. The Brain reads everything from KVS on boot — there is nothing to configure in the Brain script itself.
Step 4 — Run the Brain. Check the console for:
[CB] Brain v1.1 boot
[CB] sync endpoint: http://192.168.x.x/script/1/sync
[CB] Boot complete SWING=true POWER=true ROOM_VC=false
The sync endpoint line gives you the exact URL for your HA rest_command — IP and SCRIPT_ID already filled in.
Step 5 — Enable "Run on Startup" for the Brain script.
⚠️ Always test before enabling auto-start. Confirm the Brain is running correctly and syncing with HA before enabling Run on Startup.
For the cleanest UI experience, extract the Climate Bridge group as a standalone virtual device:
Step 1 — In the Shelly app, go to Components and locate the group:200 group created by the Setup script.
Step 2 — Tap the Settings (cog) icon on the group.
Step 3 — Select "Extract virtual group as device".
Step 4 — Open the new device card. Go to App Settings (two cogs) → Customize device card.
Step 5 — Assign your preferred parameters to the card layout slots. All components in the group can be added, removed, and reordered. A suggested starting point:
- Big parameter: Power (boolean toggle — if
add_power_toggle: true) - Small parameters: State (text:200 — full status summary in one line)
The State component is designed to fit the small slot cleanly. Customise the layout to suit your preferences — there is no fixed requirement.
| Key | Description | Default | Notes |
|---|---|---|---|
ha_token |
HA Long-Lived Access Token | 'YOUR_TOKEN' |
From HA Profile → Long-Lived Access Tokens |
ha_url |
HA base URL including port | 'http://192.168.1.X:8123' |
No trailing slash. Must be reachable from Shelly. |
entity_id |
HA climate entity ID | 'climate.your_ac' |
Must match HA exactly e.g. climate.bedroom_ac |
device_name |
Virtual device display name | 'Bedroom AC' |
Appears as device name in Shelly app |
modes |
AC mode options | ['Off', 'Auto', 'Heat', 'Cool', 'Fan', 'Dry'] |
Include only modes your AC supports. 'Off' is required. 'Fan' maps to HA fan_only. |
fan_speeds |
Fan speed options | ['Auto', 'Low', 'Medium', 'High'] |
Match your AC's HA fan_mode attribute values (capitalised). |
swing_modes |
Swing mode options | ['Horizontal', 'Vertical', 'Both', 'Off'] |
Set to [] to skip swing entirely. |
has_bthome |
Room sensor source | false |
true = Setup adds your paired BLU H&T sensor components to the group. Room data is native BTHome — Brain is not involved. false = Brain writes room temperature and humidity to virtual number components, sourced from your AC unit's HA integration (via the current_temperature and humidity attributes on the climate entity). |
bthome_ids |
BTHome component IDs | { temp: 201, humidity: 200 } |
Component IDs of your paired BLU H&T sensor. Find in Shelly app → Components. |
add_swing |
Create swing component | true |
Set false if swing_modes is empty and you want to be explicit. |
add_power_toggle |
Create boolean power toggle | true |
Adds a quick on/off toggle alongside the mode dropdown. |
add_room_humidity |
Create Room Humidity component | true |
Only applies when has_bthome: false. Set false if your AC does not report humidity and you do not want an empty component. |
temp_min |
Temperature slider minimum | 16 |
In °C |
temp_max |
Temperature slider maximum | 30 |
In °C |
icons |
Virtual component icon URLs | Icons8 confirmed URLs | Pre-filled with tested Icons8 URLs including room_t and room_h for room sensor components. Change only if you want different icons. See Credits for attribution. |
mode_titles |
Emoji titles for mode dropdown | Emoji map | Raw UTF-8 emoji displayed in the mode dropdown. |
fan_titles |
Emoji titles for fan dropdown | Emoji map | Raw UTF-8 emoji displayed in the fan dropdown. |
swing_titles |
Emoji titles for swing dropdown | Emoji map | Raw UTF-8 emoji displayed in the swing dropdown. |
debug |
Verbose console logging | false |
Set true during initial setup to trace sync activity. |
The complete HA YAML is provided in ClimateBridge_HA_Config.yaml in the repository.
The Brain prints the full sync endpoint URL on every boot — no manual lookup needed. Start the Brain and check the console:
[CB] sync endpoint: http://192.168.x.x/script/1/sync
Copy the IP and script number from this line directly into your rest_command URL. The number after /script/ is your SCRIPT_ID.
rest_command lives in configuration.yaml. Changes require a full HA restart — partial reloads (YAML reload) do not pick up rest_command changes.
HA Developer Tools → Actions → rest_command.sync_climate_bridge → Call Action
Watch the Shelly Brain console for:
[CB] sync [PUSH] hvac=cool fan=high t=24
If no log appears, verify:
- HA can reach the Shelly IP on your local network
SCRIPT_IDin the rest_command URL is correct- The Brain is running (not just saved)
- The HA automation is enabled and shows a recent "Last triggered" timestamp
Climate Bridge uses a two-script design. All configuration lives in KVS — the Brain never contains site-specific values.
The runtime engine. Runs continuously on boot. Responsibilities:
- Loads all configuration from KVS on boot
- Obtains Virtual Component handles synchronously via
Virtual.getHandle()— no RPC, no callbacks - Sets feature flags (
HAS_SWING,HAS_POWER,HAS_ROOM_VC) from handle presence - Registers HTTP endpoint
/script/{id}/syncfor inbound HA pushes — prints full URL to console on boot - Registers per-component
handle.on('change', ...)handlers for outbound sync - Debounces temperature slider input (800ms) — enum and boolean fire immediately
- Applies sync lock (1.5s) after inbound writes to suppress echo loops
- Writes VCs synchronously via
handle.setValue()— atomic, no queue, no RPC overhead - Maintains passive health tracking via
ha_fail_count - Caches last known state in
Script.storagefor reboot recovery - Builds and maintains compact status text in
text:200
Brain is fully event-driven. No polling loop — zero overhead at idle.
Unified commissioning, reconfiguration, and cleanup — four independent operation toggles. Replaces the separate Installer and Cleanup scripts from v1.0.
- Preflight validation — aborts on placeholder values or existing components (when
CREATE_VCS=truewithoutDELETE_VCS=true) DELETE_VCS— dynamically discovers and removes all Climate Bridge virtual components viaShelly.GetComponents. BTHome sensors and scripts are never touched.DELETE_KVS— removes allbridge_KVS keys. Usually not needed —SET_KVSalways overwrites.SET_KVS— seeds allbridge_KVS keys (auth, core, VC IDs, bidirectional value maps)CREATE_VCS— creates and configures all virtual components with generous settling pauses (600–800ms per operation, 2000ms between phases)- Assembles
group:200in locked UI display order - Adds BTHome sensor icons if
has_bthome: true - Self-stops on completion via
Shelly.getCurrentScriptId()
All KVS keys use the bridge_ prefix. Seeded by the Setup script on install.
| Key | Contents | Written by |
|---|---|---|
bridge_auth |
HA Long-Lived Access Token | Setup |
bridge_core |
HA URL, entity ID, flags (debug, print_yaml, has_bthome) |
Setup |
bridge_vc |
Virtual component ID map | Setup |
bridge_schema |
Spec version string | Setup |
bridge_map_mode_ha |
HA → Shelly mode lookup | Setup |
bridge_map_mode_sh |
Shelly → HA mode lookup | Setup |
bridge_map_fan_ha |
HA → Shelly fan lookup | Setup |
bridge_map_fan_sh |
Shelly → HA fan lookup | Setup |
bridge_map_swing_ha |
HA → Shelly swing lookup (conditional) | Setup |
bridge_map_swing_sh |
Shelly → HA swing lookup (conditional) | Setup |
Total: 10 keys (8 without swing). Well within the Shelly 100-key KVS limit. All values confirmed under 253 bytes.
Script.storage — last_state (1 slot): cached AC state JSON for reboot recovery. Written by Brain on every successful inbound push.
Brain boots but status shows ❌ immediately
HA is not sending pushes, or the initial syncFromHA call on boot failed. Verify HA can reach the Shelly IP, and that the Brain endpoint URL and SCRIPT_ID in your rest_command match the URL printed by the Brain on boot.
Status shows
Shelly app changes don't reach HA
Check the Brain console for [CB] HA→ lines. If outbound calls are firing but HA is not responding, check the HA token is valid (Long-Lived Access Tokens expire if manually revoked). Run Setup with SET_KVS=true to update the token without touching the VCs.
HA push arrives but VCs don't update
Check for [CB] sync [PUSH] lines in the Brain console. If the push is received but values look wrong, check the bridge_map_mode_ha KVS key matches your HA entity's hvac_modes values — particularly fan_only vs any custom fan-mode naming your integration uses.
Setup aborts on preflight
Either SITE_CONFIG still contains placeholder values (YOUR_TOKEN, 192.168.1.X, climate.your_ac) or text:200 already exists and DELETE_VCS is false. Set DELETE_VCS=true for a full reinstall, or set SET_KVS=true only to update KVS without touching components.
SCRIPT_ID is unknown
Start the Brain script — it prints the full sync URL on every boot: [CB] sync endpoint: http://IP/script/N/sync. Update your HA rest_command URL and do a full HA restart.
HA automation not triggering
rest_command requires a full HA restart after adding to configuration.yaml — a YAML reload is not sufficient. Confirm the automation is enabled and the entity trigger is set to the correct entity ID.
Push failing silently — HA shows no errors
Check your payload in HA Developer Tools → Template. If any value renders as None, your AC integration does not report that attribute. Use | int(0) for current_temperature and humidity — not | default(). See the YAML section above.
One Shelly hosts multiple AC entities. A device selector virtual component (enum:204) switches the active entity. Shared controls, per-entity state cache.
All entities in a multi-device installation must share identical capabilities (same modes, fan speeds, swing options).
Test harness for the Brain. Injects synthetic HA push events and logs sync behaviour without requiring a live HA connection. (Distinct from the Showcase — the Showcase demonstrates the UI; the Simulator tests the Brain sync engine.)
Eco / Sleep / Boost presets stored in KVS. Single-tap shortcuts to common temperature + mode combinations.
Optional addon using Shelly EM energy monitoring to detect AC compressor state (idle vs active) for display in status text.
- Heat/cool temperature offset overrides
- Energy tracking and cost display
- Terminal console (
text:202) for runtime diagnostics
Icons
Component icons provided by Icons8. The default icon set in SITE_CONFIG.icons uses confirmed-working Icons8 URLs tested on Shelly hardware. Icons8 attribution is required under their free-use licence — please retain it if you use the default URLs or substitute your own Icons8 selections.
Shelly Script Foundation Climate Bridge is built on patterns and examples from the official Shelly Script Examples repository by Allterco Robotics. The KVS loader pattern, serial RPC queue, and virtual component creation patterns are adapted from those examples.
Shelly Academy Advanced scripting knowledge, best practices, and the deep understanding of the Shelly Virtual Component API that made this project possible came directly from Shelly Academy. Thank you to all the instructors for the exceptional course content.
Shelly Academy — Emre
A special thank you to Emre at Shelly Academy, whose example script was the direct inspiration for Climate Bridge. His example demonstrated the core pattern at the heart of this project: using a Home Assistant rest_command to push state into a Shelly device via HTTP RPC, and handling it on the Shelly side using a Virtual Component. That approach — HA as the push source, Shelly as the receiver — is the architectural foundation that Climate Bridge builds on and extends into a full bidirectional sync engine.
- Brain: Virtual handle API (
Virtual.getHandle+handle.setValue) replaces RPC-based VC queue — synchronous writes, no queue, no callbacks, zero RPC overhead on inbound sync - Brain:
handle.on('change', ...)per-component handlers replace globaladdStatusHandler— cleaner outbound path, no component filtering needed - Brain: Feature flags (
HAS_SWING,HAS_POWER,HAS_ROOM_VC) now set synchronously from handle presence — asyncprobeFeaturesRPC chain eliminated - Brain: Source filter adds
'sys'— fixes echo loop bug wheresetValue()writes (which carrysource='sys') were not suppressed by the outbound handler - Brain: Inbound body parsing handles both pre-parsed objects and raw strings — fixes silent failure when Shelly firmware pre-parses JSON from
content_type: application/jsonrequests - Brain: Sync endpoint URL (including IP and SCRIPT_ID) printed to console on every boot
- Setup: Unified script replaces separate Installer and Cleanup — four independent operation toggles (
DELETE_VCS,DELETE_KVS,SET_KVS,CREATE_VCS) - Setup: Dynamic VC discovery via
Shelly.GetComponents— no hardcoded component list for deletion - Setup:
add_room_humidityflag — skip humidity VC if AC does not report it - Setup:
room_tandroom_hicon slots added — BTHome sensor components styled on install - Setup: Generous settling pauses between phases (2000ms) — improved stability on all devices
- HA Config:
| int(0)replaces| default()forcurrent_temperatureandhumidity— fixes silent push failures when AC integration returns PythonNonefor unreported attributes - HA Config: Entity variable
{% set e = 'ENTITY_ID' %}— cleaner payload, single point of edit
- Initial release — single-device package
- Bidirectional sync: outbound debounce (800ms), inbound sync lock (1.5s)
- Configurable capabilities: modes, fan speeds, swing modes, power toggle
- BTHome and virtual number paths for room temperature and humidity
- Passive health tracking with status glyph (📶 /
⚠️ / ❌) - Reboot recovery via Script.storage cache
- Preflight-guarded Installer with self-stop
- Cleanup utility with dry-run mode
⚡ SPARK_LABS — Shelly Powered Automation Reliable Kontrol
Technician, Installer & Shelly Academy Graduate
Turning everyday Shelly devices into truly smart virtual devices and appliances.




