Integrating Midea And Clivet Heat Pumps With Shelly Smart Control Via Modbus Rtu

image-20261010-160354.png

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 (@meta and Script.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

9600

Serial format

8N1

Remote Modbus Slave ID

Persistent managed VC; integer 1–247, initial value 1

Local Shelly Serial / Modbus client ID

100 by default; verify the installed add-on

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

10000 ms between completed cycles

Request gap

100 ms

Write settling delay

700 ms

Retry interval

10000 ms

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

zone

Boolean

Midea/Clivet Zone 1 Enable

Enable/disable the zone 1 water request (register 0, bit 1)

2

dhw

Boolean

Midea/Clivet DHW Enable

Enable/disable DHW (register 0, bit 2)

3

slaveId

Number

Modbus Slave ID

Persisted, editable Modbus address (1–247)

4

water

Number

Midea/Clivet Zone 1 Water Target

Zone 1 leaving-water target (register 2, low byte)

5

dhwTarget

Number

Midea/Clivet DHW Target

DHW target (register 4)

6

inlet

Number

Midea/Clivet Inlet Temperature

Return/inlet water temperature (register 104)

7

outlet

Number

Midea/Clivet Outlet Temperature

Leaving/outlet water temperature (register 105)

8

tank

Number

Midea/Clivet Tank Temperature

Optional tank/T5 reading (register 115)

9

status

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

1

Maximum

247

Step

1

New-installation default

1

Persisted across restarts

true

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:

https://github.com/ALLTERCO/shelly-script-examples/blob/main/modbus/Midea/midea-clivet-r32-pro-modbus-vc.shelly.js

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

  1. Confirm the exact R32 controller/register map and leaving-water control for zone 1.

  2. Wire the RS-485 A/B terminals as documented, and connect the Pro Modbus Add-on to a compatible host.

  3. Open the Shelly device's local web interface; enable/select the RS-485 add-on and reboot if prompted.

  4. Confirm that the installed firmware supports managed Virtual Components and has capacity for nine components.

  5. If upgrading, back up scenes and remove only verified obsolete fixed-ID components before creating the managed version.

  6. Create one script, paste the complete .shelly.js source and preserve the first-line @meta declaration exactly.

  7. Leave enableWrites: false, save and start the script. The firmware will allocate nine managed Virtual Components.

  8. Set Modbus Slave ID in Shelly to the controller's actual bus address (1–247). This value will be persisted across restarts.

  9. Compare reported register values, temperatures, mode, and diagnostics with the physical controller.

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

JavaScript
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:

Integration@shelly.com