Bring heating, domestic hot water and operating information from a compatible Midea or Clivet heat pump into Shelly Smart Control through a local RS-485 connection.
The integration uses a compatible Shelly Pro host, the Shelly Pro Modbus Add-on and one standalone Shelly script. It provides exactly nine firmware-managed Virtual Components, covering zone 1, domestic hot water, water temperatures, operating diagnostics and a new Modbus Slave ID setting that can be changed directly from the Shelly interface.
The original heat-pump controller continues to manage compressor operation, operating priorities, defrost and the system’s built-in protections. Shelly reads the controller’s information and applies supported commands through Modbus RTU.
Validation scope: The earlier fixed-ID version was tested on a real heat pump on 10 October 2026. The latest version replaces runtime VC provisioning with firmware-managed components and adds a configurable Modbus Slave ID. Its updated startup, component lifecycle and address-selection behavior still require a fresh real-device smoke test. Automated GitHub checks have passed, but do not replace physical validation.
Supported heat pumps. The script targets the Midea R32 / 171H120F-compatible register layout, with zone 1 configured for leaving-water temperature control.
Compatibility depends on the installed controller and its register map.
| Equipment | Compatibility with this script |
|---|---|
| Midea R32 air-to-water heat pumps | Supported when the wired controller exposes the documented register layout and zone 1 uses leaving-water control. |
| Clivet heat pumps using the compatible Midea R32 platform | Supported when the controller, connection and register layout match this profile. |
| Other brands using the same controller platform | Require confirmation of the exact register map and control configuration. |
| Midea or Clivet R290 equipment | Requires a profile for its particular controller and register layout. |
| Clivet SWAN-2 domestic hot water units | Requires a separate profile. |
| Installations using room-temperature control | Require a profile designed for that control arrangement. |
A manufacturer name or an RS-485 terminal alone does not establish compatibility. Check the heat pump’s model, wired controller, service documentation and Modbus table.
The controller-version check built into the script provides an additional safeguard after the correct profile has been identified.
What you can control and monitor. The updated integration provides four heat-pump controls and one independent configuration setting:
-
Enable or disable the zone 1 water-control request.
-
Enable or disable domestic hot water operation.
-
Select the controller’s Modbus Slave ID (1–247) from an editable, persistent Number component. This is a communications setting, not a Modbus command to change the controller’s own address.
-
Adjust the zone 1 water-temperature target.
-
Adjust the domestic hot water target.
The four equipment controls remain Zone 1 Enable, DHW Enable, Zone 1 Water Target and DHW Target. The new Modbus Slave ID replaces the previous Silent Mode control. The integration also reports inlet, outlet and (if configured) tank temperatures, plus a Status field containing the active Modbus address, operating mode, compressor frequency, fault number, controller version and defrost indication.
Heating, cooling, Auto and any required Silent Mode settings remain on the original controller. Shelly displays the actual operating state; it does not provide a Silent Mode toggle in this version.
Hardware and software requirements. You need:
-
A compatible heat pump and wired controller.
-
A Shelly Pro host supported by the Pro Modbus Add-on.
-
A Shelly Pro Modbus Add-on.
-
Suitable twisted-pair RS-485 cable.
-
Firmware with working Serial, MbRtuClient, Shelly Script and managed Virtual Components (
@metaandScript.getVcHandle()). Do not assume all firmware versions starting with 2.0.0 support the managed VC lifecycle. -
Capacity for nine firmware-managed Virtual Components. Existing manually provisioned components are not automatically adopted by the new script.
-
A connection to Shelly Smart Control for app access.
Choose a Shelly Pro host explicitly supported by the Pro Modbus Add-on and the required APIs. Product variants such as Pro EM-50, Pro 3EM-120, Pro 3EM-400, Pro 1 and Pro 2 should be checked against the current Shelly compatibility information, firmware and available expansion interface before installation.
The bridge runs locally on the Shelly device. RS-485 communication does not require a heat-pump cloud account. Remote access through Shelly Smart Control uses the Shelly device’s network and cloud connection.
Connecting the RS-485 interface. On the wired controller covered by this profile, the connection is:
| Heat-pump controller | Shelly Pro Modbus Add-on |
|---|---|
| H2 / A+ | A |
| H1 / B− | B |
| Signal reference, where specified | Connect according to the controller’s wiring documentation and the Add-on’s reference requirements. |
Check these terminal assignments against the exact controller manual before connecting the cable. Other terminals marked A or B may serve a different purpose on another controller.
Use twisted-pair cable and follow the installation documentation for cable shielding, signal reference and termination. Keep one active Modbus client on the line. Disconnect commissioning tools before enabling the Shelly bridge.
The Modbus connection carries communication signals. The heat pump retains its normal electrical supply and original controller.
Communication settings
The latest script uses these defaults:
| Parameter | Default / behavior |
|---|---|
| Protocol | Modbus RTU over RS-485 |
| Baud rate |
|
| Serial format |
|
| Remote Modbus Slave ID | Persistent managed VC; integer 1–247, initial value 1 |
| Local Shelly Serial / Modbus client ID |
|
| Reading | FC03: Read Holding Registers |
| Writing | FC06: Write Single Register (disabled by default) |
| Optional write method | FC16 for a single register, only if explicitly configured |
| Polling pause |
|
| Request gap |
|
| Write settling delay |
|
| Retry interval |
|
The remote Modbus Slave ID and local Shelly Serial ID are different identifiers. The Modbus Slave ID VC selects which existing controller address receives Shelly requests. CONFIG.serialId selects the Shelly Serial/MbRtuClient interface. For example, the controller may have address 16 while the local Serial component remains 100.
All reads in this profile use Holding Registers, FC03, including temperatures and diagnostics. The register addresses below are wire offsets, not 4xxxx notation.
The nine firmware-managed Virtual Components
The script declares these roles in its first-line @meta declaration, and the Shelly firmware creates/reconciles them before the script runs. It uses Script.getVcHandle(role) to bind them; component IDs are allocated by the firmware, not fixed at 220–228. The vcBase setting and runtime Virtual.Add logic have been removed.
| # | Managed role | Type | Name shown in Shelly | Function |
|---|---|---|---|---|
| 1 |
| Boolean | Midea/Clivet Zone 1 Enable | Enable/disable the zone 1 water request (register 0, bit 1) |
| 2 |
| Boolean | Midea/Clivet DHW Enable | Enable/disable DHW (register 0, bit 2) |
| 3 |
| Number | Modbus Slave ID | Persisted, editable Modbus address (1–247) |
| 4 |
| Number | Midea/Clivet Zone 1 Water Target | Zone 1 leaving-water target (register 2, low byte) |
| 5 |
| Number | Midea/Clivet DHW Target | DHW target (register 4) |
| 6 |
| Number | Midea/Clivet Inlet Temperature | Return/inlet water temperature (register 104) |
| 7 |
| Number | Midea/Clivet Outlet Temperature | Leaving/outlet water temperature (register 105) |
| 8 |
| Number | Midea/Clivet Tank Temperature | Optional tank/T5 reading (register 115) |
| 9 |
| Text | Midea/Clivet Status | Communication state, selected slave, operating state and diagnostics |
The new allocation is two Boolean, six Number and one Text component. The former Silent Mode Boolean is not created. The installation still occupies nine of the device's ten available VC slots, with no additional Group component.
Choosing the Modbus Slave ID
The Modbus Slave ID managed component is configured as follows:
| Property | Value |
|---|---|
| Type | Number |
| Minimum |
|
| Maximum |
|
| Step |
|
| New-installation default |
|
| Persisted across restarts |
|
| UI | Editable numeric field |
Suppose the physical heat-pump controller is already configured for Modbus address 16. Open the Modbus Slave ID component in Shelly and set its value to 16. The script will target address 16 without requiring an edit to the JavaScript.
Important: This setting does not program the controller's physical address; it only selects the destination of Shelly's outgoing Modbus requests. Configure the controller itself using its manufacturer's approved procedure, then select the same address in Shelly.
Changing this setting triggers a fresh synchronization: the script clears cached register values and command baselines, prevents old pending callbacks/timers from updating the new target's state, and holds control until current readings are available from the newly selected slave. The status is updated during the transition; the chosen address is retained after a Shelly restart. Invalid, fractional or out-of-range values are rejected. A Modbus write that has already been transmitted cannot be cancelled.
Migrating from the older fixed-ID version
If you are upgrading from a script that created VCs with Virtual.Add at fixed IDs 220–228, back up scripts, scenes and automations. Stop the old script and identify its old manually provisioned components. Remove only confirmed obsolete Midea/Clivet components if additional free capacity is needed. Managed VCs do not automatically adopt old components, and their firmware-assigned numeric IDs may differ. Update any scenes or third-party integrations that refer to fixed component IDs.
Installing the script
The current implementation is included in the Shelly upstream contribution:
Only midea-clivet-r32-pro-modbus-vc.shelly.js is installed on Shelly; no Node.js tests or Markdown documentation need to be uploaded to the device. The linked PR contains one changed file and is still subject to upstream review.
Installation procedure
-
Confirm the exact R32 controller/register map and leaving-water control for zone 1.
-
Wire the RS-485 A/B terminals as documented, and connect the Pro Modbus Add-on to a compatible host.
-
Open the Shelly device's local web interface; enable/select the RS-485 add-on and reboot if prompted.
-
Confirm that the installed firmware supports managed Virtual Components and has capacity for nine components.
-
If upgrading, back up scenes and remove only verified obsolete fixed-ID components before creating the managed version.
-
Create one script, paste the complete
.shelly.jssource and preserve the first-line@metadeclaration exactly. -
Leave
enableWrites: false, save and start the script. The firmware will allocate nine managed Virtual Components. -
Set Modbus Slave ID in Shelly to the controller's actual bus address (1–247). This value will be persisted across restarts.
-
Compare reported register values, temperatures, mode, and diagnostics with the physical controller.
-
After verifying the controller version and safety/temperature limits, optionally enable writes and configure startup execution.
Script configuration
The current script contains the following CONFIG block (notice that slaveId and vcBase are no longer configuration properties):
var CONFIG = { profile: 'midea-r32-171h120f', serialId: 100, baud: 9600, format: '8N1', enableWrites: false, expectedControllerVersion: null, hasDhwTank: false, allowCooling: false, waterMin: 20, waterMax: 60, coolingMin: 5, coolingMax: 25, dhwMin: 20, dhwMax: 60, writeFunction: 6, pollMs: 10000, retryMs: 10000, gapMs: 100, settleMs: 700 }; Unlike the INNOVA example, this bridge can configure its local Serial mode using Serial.SetConfig when necessary; the device may request a reboot. Do not confuse that local Serial setting with the remote Modbus Slave ID, which is selected in the managed component.
Keep enableWrites: false until the first successful physical synchronization. The script then reads the controller state and publishes the relevant values without issuing equipment-control writes.
The logs report the controller-version register and readiness; for example:
[Midea] Controller version (register 131) = [Midea] READY: 9 components synchronized; read-only mode Set expectedControllerVersion to the actual numeric value read at register 131 (not 131 itself). This check is an additional guard, not automatic model identification. Configure hasDhwTank, allowCooling, and the appropriate safe limits for the installed plant. Only then consider setting enableWrites: true and restarting the script.
The writable equipment controls are Zone 1 Enable, DHW Enable, Zone 1 Water Target, and DHW Target. Modbus Slave ID is a local communication setting; it is never written as an address-changing register on the heat pump.
Domestic hot water configuration
Set hasDhwTank: true when the installation includes the tank and its correctly configured T5 sensor.
With this setting enabled, the bridge reads the tank temperature and DHW limits, and permits DHW commands subject to the controller’s state and configured limits.
When hasDhwTank remains false, DHW writes are blocked and tank-temperature and DHW-limit reads are skipped. All nine managed components still exist, but the tank-temperature component should be considered unavailable, not a valid measurement, until a supported T5 sensor is configured.
Heating, cooling and target limits
The default configured ranges are:
| Target | Default configured range |
|---|---|
| Heating water | 20–60 °C |
| Cooling water | 5–25 °C |
| Domestic hot water | 20–60 °C |
These settings must match the installed equipment and system design. Each requested target must also fall within the controller’s current limits.
The permitted range is the intersection of the configured range and the live controller range.
For manual water-target control, select Heat or Cool on the original controller. Cooling requires allowCooling: true and an installation commissioned for cooling.
Manual zone 1 target changes are blocked in Auto mode or while the zone 1 weather-compensation curve is active. The controller continues to manage the weather curve.
An active fault blocks commands. The room-control flag also blocks writes for this leaving-water profile.
Registers used by the integration
| Address | Meaning | Handling |
|---|---|---|
| 0, bit 1 | Zone 1 water enable | Mask 0x0002 |
| 0, bit 2 | DHW enable | Mask 0x0004 |
| 1 | Configured mode | 1 Auto, 2 Cool, 3 Heat; read only |
| 2, low byte | Zone 1 water target | Preserves the zone 2 high byte |
| 4 | DHW target | Whole degrees Celsius |
| 5, bit 6 | Silent-mode flag | Not exposed as a writable Virtual Component |
| 5, bit 12 | Zone 1 weather curve | Used to guard manual target writes |
| 100 | Compressor frequency | Included in Status |
| 101 | Actual operating mode | Included in Status |
| 104 | Inlet water temperature | Signed 16-bit, whole degrees Celsius |
| 105 | Outlet water temperature | Signed 16-bit, whole degrees Celsius |
| 115 | Tank temperature | Optional T5 reading |
| 124 | Current fault | Raw fault number |
| 128, bit 1 | Defrost indication | Included in Status |
| 131 | Controller version | Read and compared with configuration |
| 201/202 | Cooling upper/lower limits | Zone 1 low bytes |
| 203/204 | Heating upper/lower limits | Zone 1 low bytes |
| 207/208 | DHW upper/lower limits | Used when DHW is configured |
Temperature readings use signed integers in whole degrees Celsius. Target commands use integer-degree steps.
FC06 is the default write function. Set writeFunction: 16 only when the exact controller requires FC16. In that configuration, the script writes a one-register list.
How commands are applied
Before writing, the script refreshes the relevant control state, fault information and target limits, then reads the destination register again.
Shared registers use a masked read-modify-write operation. Changing the zone 1 target preserves the current zone 2 target byte. Changing an enable flag preserves the other flags in the same word.
After writing, the bridge waits for the settling delay, reads the register back and publishes the controller’s reported value. An FC06 response alone does not prove that the physical heating system changed state.
A confirmed write means the controller reported the requested register value. Actual heating or DHW operation still follows the heat pump’s priorities and operating cycles.
Unconfirmed writes are logged. The script does not blindly repeat a failed write or switch write functions automatically.
Status and communication recovery
The text Midea/Clivet Status component reports:
-
Online, read-only or control state.
-
The selected Modbus Slave ID (
SID=). -
Actual operating mode.
-
Compressor frequency.
-
Current fault number.
-
Controller version.
-
Defrost indication.
-
Relevant configuration or command notices.
Recognized actual operating modes are Off, Cool, Heat and DHW. Other values appear with their raw mode number. A typical status may look like:
ONLINE | SID=16 | READ ONLY | Heat | Hz=45 | fault=0 | controller=47 This example is illustrative; the mode, compressor frequency, controller version and selected address depend on the installation.
On a communication failure, Status begins with:
OFFLINE | last readings stale Commands are blocked while communication is unavailable. Previously displayed temperatures remain visible as the last readings.
After startup or reconnection, the bridge performs a complete physical synchronization before resuming control. Stored interface values and commands entered while offline are not replayed. Changing the Modbus Slave ID also invalidates previous controller snapshots and pending callbacks and restarts the synchronization process; an already-sent physical command cannot be undone.
Using the components in Shelly Smart Control
Arrange the controls and measurements around the system’s main functions:
| Dashboard function | Components |
|---|---|
| Heating or cooling zone | Zone 1 Enable, Zone 1 Water Target, Outlet Temperature |
| Domestic hot water | DHW Enable, DHW Target, Tank Temperature |
| Water-temperature monitoring | Inlet Temperature and Outlet Temperature |
| Modbus device selection | Modbus Slave ID (persisted Number component) |
| System diagnostics | Status |
Keep Status visible alongside the controls so communication problems and command restrictions are easy to identify.
The components can also support scenes and automations, such as adjusting DHW targets during selected periods or coordinating heating requests with a tariff schedule or photovoltaic-surplus signal. Silent Mode is not available as a Shelly command in this revision; configure it through the original controller if the model supports it. The Modbus Slave ID is an installation setting and should not be changed automatically as part of normal heating logic.
Automations remain subject to the same controller checks and temperature limits as manual commands.
Adding electrical energy monitoring
A Shelly Pro EM-50 can provide independent electrical measurements for a suitable single-phase heat-pump supply. It offers two current-transformer measurement channels.
For a three-phase installation, select a suitable three-phase metering device.
Native electrical measurements are separate from the bridge’s nine virtual components. They can be used to compare consumption with heating operation and DHW cycles.
Calculating COP additionally requires thermal-output measurement or suitable water-flow and temperature measurements.
Troubleshooting
If communication appears offline, check Midea/Clivet Status, the script logs and the selected Modbus Slave ID before changing other parameters.
| Symptom | What to check |
|---|---|
| No Modbus response | H1/H2 wiring, A/B polarity, persisted Modbus Slave ID (1–247), baud rate, serial format, Add-on selection and local Serial component ID |
| Intermittent communication | Cable routing, termination, signal reference and another active Modbus client |
| Illegal register address | Controller family and exact register layout |
| Implausible temperatures | Register selection and signed whole-degree decoding |
| Status remains read-only | enableWrites, expected controller version and room-control flag |
| Water target is rejected | Heat/Cool selection, weather curve, cooling configuration and permitted limits |
| DHW control is unavailable | hasDhwTank, installed tank, T5 sensor and controller configuration |
| Component setup stops | Managed-VC firmware support, nine free VC slots, valid persisted Modbus Slave ID, and assigned component handles |
| A write is not confirmed | Controller response, operating restrictions and readback information in the log |
| Fault number appears | Interpret the raw code using the exact heat-pump model’s service documentation |
Source and technical references
The PR updates only the Shelly-installable script. The earlier documentation and Node.js tests remain in the repository but are not changed by this pull request. The new managed-component startup and live slave selection should be verified on the actual Pro host and heat pump before deployment.
We Value Your Feedback!
Thank you for taking the time to read our article! Was it helpful or interesting?
Your insights can help us improve. We’d be grateful for any feedback. If you have a moment,
please share it with us at the following email: