Skip to content

Repository files navigation

⚡️ SPARK_LABS: Climate Bridge v1.1

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

Device Card

📁 Note: Emoji rendering may vary between Android, iOS, and desktop — the glyphs are functionally identical across platforms.


🌡️ What is this?

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.


Main Controls

🔧 The Problem

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.


🔀 How It Works


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.


💻 Hardware

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.


✨ Features

  • 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 climate entity 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.

📱 Virtual Device UI

Component Table

# 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.

AC Mode
AC Mode
Fan Speed
Fan Speed
Swing
Swing

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.

Status Text (text:200)

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: ↕️ Vertical · ↔️ Horizontal · 🔀 Both · (omitted when Off)

Room data prefix: 🏠 (precedes room temperature and humidity when present)

Health glyphs: 📶 Healthy · ⚠️ Warning (1–2 failed calls) · ❌ Down (3+ failed calls)

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.

Virtual Device Card Layout

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.


📦 Repository Contents

Release Scripts

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 separate Installer and Cleanup scripts are retired.

Setup Operation Toggles

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


🚀 Installation

Prerequisites

  • 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 climate entity 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: false in SITE_CONFIG.

⚠️ Reinstalling or changing configuration? Use ClimateBridge_Setup_v1.0.js with DELETE_VCS=true to remove existing components before creating new ones. The Setup script will abort if it detects components already installed and DELETE_VCS is false.


⚠️ Security — HA Long-Lived Access Token: Your HA token is stored in the Shelly device's KVS under the key bridge_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=true and the new token in SITE_CONFIG, or edit the bridge_auth KVS key directly in the Shelly web UI (Scripts → KVS) and restart the Brain. Editing bridge_auth alone is safe. Be cautious when editing any other bridge_ 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.


Phase 1 — Home Assistant Setup

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/sync

The number after /script/ is your SCRIPT_ID. Use this URL in your HA rest_command.

If you also set print_yaml: true in SITE_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 the ClimateBridge_HA_Config.yaml file 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. Remove current_temp and humidity from 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 Python None from state_attr — it only catches undefined variables. If your AC does not report current_temperature or humidity, those attributes return None, which passes through | default() unchanged and renders as the literal string None in the JSON payload, breaking the push silently. The | int(0) filter correctly converts None to 0. The Brain suppresses 0 humidity 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 None anywhere, your AC integration does not report that attribute — use | int(0) as shown above.

Replace the placeholders:

  • SHELLY_IP → your Shelly device's IP address
  • SCRIPT_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: silent

mode: 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_ID placeholder has been replaced with the actual script number
  • The automation shows a recent "Last triggered" timestamp

Phase 2 — The Setup Script

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 Token
  • ha_url — your HA URL e.g. http://192.168.1.X:8123
  • entity_id — your climate entity e.g. climate.bedroom_ac
  • device_name — display name for the virtual device e.g. Bedroom AC
  • modes, 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 available hvac_modes and fan_modes attributes. Only include modes your AC actually supports.

⚠️ HA uses fan_only — Climate Bridge shows Fan. HA's internal name for fan-only mode is fan_only. Climate Bridge maps this automatically. In SITE_CONFIG.modes you 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.


Phase 3 — The Brain

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.


Phase 4 — Virtual Device Card (Optional — Shelly Premium)

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.


⚙️ SITE_CONFIG Reference

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.


🏠 Home Assistant Configuration Reference

The complete HA YAML is provided in ClimateBridge_HA_Config.yaml in the repository.

Finding your SCRIPT_ID

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.

After any configuration.yaml change

rest_command lives in configuration.yaml. Changes require a full HA restart — partial reloads (YAML reload) do not pick up rest_command changes.

Verifying the push

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:

  1. HA can reach the Shelly IP on your local network
  2. SCRIPT_ID in the rest_command URL is correct
  3. The Brain is running (not just saved)
  4. The HA automation is enabled and shows a recent "Last triggered" timestamp

🧠 Architecture

Climate Bridge uses a two-script design. All configuration lives in KVS — the Brain never contains site-specific values.

Brain (ClimateBridge_Brain_v1.1.js)

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}/sync for 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.storage for reboot recovery
  • Builds and maintains compact status text in text:200

Brain is fully event-driven. No polling loop — zero overhead at idle.

Setup Script (ClimateBridge_Setup_v1.0.js)

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=true without DELETE_VCS=true)
  • DELETE_VCS — dynamically discovers and removes all Climate Bridge virtual components via Shelly.GetComponents. BTHome sensors and scripts are never touched.
  • DELETE_KVS — removes all bridge_ KVS keys. Usually not needed — SET_KVS always overwrites.
  • SET_KVS — seeds all bridge_ 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:200 in locked UI display order
  • Adds BTHome sensor icons if has_bthome: true
  • Self-stops on completion via Shelly.getCurrentScriptId()

🗄️ KVS Reference

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.storagelast_state (1 slot): cached AC state JSON for reboot recovery. Written by Brain on every successful inbound push.


🔧 Troubleshooting

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 ⚠️ then recovers Intermittent HA connectivity — normal during HA restarts or brief network interruption. Status resets to 📶 automatically on the next successful HA call or inbound push.

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.


🗺️ Roadmap

v1.2 — Multi-Device Package

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).

v1.2 — Simulator Script

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.)

v2.0 — Preset Modes

Eco / Sleep / Boost presets stored in KVS. Single-tap shortcuts to common temperature + mode combinations.

v2.0 — Power-Based Idle Detection

Optional addon using Shelly EM energy monitoring to detect AC compressor state (idle vs active) for display in status text.

Future

  • Heat/cool temperature offset overrides
  • Energy tracking and cost display
  • Terminal console (text:202) for runtime diagnostics

🤝 Credits & Attribution

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.


📝 Changelog

v1.1 — March 2026

  • 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 global addStatusHandler — cleaner outbound path, no component filtering needed
  • Brain: Feature flags (HAS_SWING, HAS_POWER, HAS_ROOM_VC) now set synchronously from handle presence — async probeFeatures RPC chain eliminated
  • Brain: Source filter adds 'sys' — fixes echo loop bug where setValue() writes (which carry source='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/json requests
  • 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_humidity flag — skip humidity VC if AC does not report it
  • Setup: room_t and room_h icon 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() for current_temperature and humidity — fixes silent push failures when AC integration returns Python None for unreported attributes
  • HA Config: Entity variable {% set e = 'ENTITY_ID' %} — cleaner payload, single point of edit

v1.0 — March 2026

  • 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

Built on the Foundations of Shelly Academy

⚡ SPARK_LABSShelly Powered Automation Reliable Kontrol

Technician, Installer & Shelly Academy Graduate

github.com/Nc-eW22

Turning everyday Shelly devices into truly smart virtual devices and appliances.

About

⚡ SPARK_LABS: Bring native AC control into the Shelly Smart Control app — Using Home Assistant as an invisible local bridge. Bidirectional sync. No cloud. No proprietary app.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages