logo elektroda
logo elektroda
X
logo elektroda

Teardown of IRIS dongle and automating heat pump water heater

paulp 2079 0

TL;DR

  • Teardown of the Lowe’s IRIS dongle for a CEA 2045 heat pump water heater, showing its decoder IC and Inventek ISM43362 Wi‑Fi module.
  • UART access through an ESP32 exposed the dongle’s HTTPS client, DNS lookup to energysmartwaterheater.com, and the SSL failure that blocked the dead cloud service.
  • A fixed EnergySmartBridge Docker setup, with nginx:1.24 instead of nginx:latest, plus MQTT and Home Assistant integration, restored mode control.
  • The bridge publishes Home Assistant config on homeassistant/water_heater/C47F5101D65F/config and supports eco, heat_pump, electric, and off modes.
  • The dongle only reconnects every 5 minutes, and the heater’s C setting behaved strangely, so validation takes patience.
Generated by the language model.
ADVERTISEMENT
📢 Listen (AI):
  • Today, we are going to hack a ... water heater. This time, minimal soldering will be involved.
    Long story short, about two years ago, I got myself a new heat pump water heater.
    A heat pump heater is about 3x more efficient than an electric one, and everything is nice, except for the compressor fan. After the evening shower, it runs for another hour or two, making a rattling noise - the manufuckturer (sic!) said it is normal. A solution was to manually come to the laundry room and change the mode to electric. Then, in the morning, change it back to the heat pump, rinse, repeat, defeat the purpose. So I want it to go to electric right after the evening shower (humidity sensor) and turn back to the heat pump at about 4 am.

    The heater is equipped with a CEA 2045 port for remote control*. (Note: The port has 240V pins, so be extremely cautious!) Lowes even had a cloud service to use it. Neat, eh? But they sunset it before I even got my heater. It used to work via an add-on dongle, IRIS. You can get them on eBay pretty cheap since they are of no use anymore. Not for a curious mind, though.

    So, I got an IRIS dongle and opened it immediately. It has an IC to decode the CEA protocol and an ISM43362 Wi-Fi module from Inventeksys to send the data away. Right next to the Wi-Fi module, there are two holes for the RX and TX pins (the usual 0.1" header, marked with 1) and the 3.3V / GND pins on the 5-pin header, which is 2mm, marked with 2 (pin3 - 3.3V, pin 4 - GND, pins 1,2 show 3.3V as well, but they are not connected to the VCC pin of the wifi module - use at your own risk).
    Close-up of an opened IRIS hardware key with visible electronic components and wiring.

    I hooked up a UART adapter (I used ESP32) to take a peek at what was going on. The config for ESP32 is below.
    Spoiler:
    esphome:
    name: esphome-water_heater
    friendly_name: Water Heater
    platform: esp32
    board: esp32doit-devkit-v1


    # Enable logging
    logger:
    level: VERBOSE
    baud_rate: 0
    # Enable Home Assistant API
    api:

    ota:

    wifi:
    ssid: "mySSID"
    password: "myPassword"
    use_address: 192.168.0.30
    ap:
    ssid: "Water Heater Fallback Hotspot"
    password: "0zr7bHSn1epQ"

    web_server:
    port: 80

    uart:
    id: my_uart
    tx_pin: GPIO1
    rx_pin: GPIO3
    baud_rate: 115200
    debug:
    direction: BOTH
    dummy_receiver: true
    after:
    delimiter: "\n"
    sequence:
    - lambda: UARTDebug::log_string(direction, bytes);

    And it's alive. Initially, it tries to connect to https://energysmartwaterheater.com. This service is no longer available, so I had to add an A-record to my DNS** (I use Pihole, but it can be anything) and divert https://energysmartwaterheater.com to 192.168.0.1 (or wherever you will be hosting the bridge). But it's not so easy - now it shows an SSL error:
    Spoiler:
    [06:00:33][D][uart_debug:158]: <<< "[BOOT AC] Enabled\r\n"
    [06:00:33][D][uart_debug:158]: <<< "[JOIN ] mySSID"
    [06:00:40][D][uart_debug:158]: <<< ",192.168.0.12,0,0\r\n"
    [06:00:40][D][uart_debug:158]: <<< "\r\n"
    [06:00:40][D][uart_debug:158]: <<< " ____ __ __ _ _____ _\r\n"
    [06:00:40][D][uart_debug:158]: <<< " ___ / ___| \\ \\ / /(_)| ___|(_)\r\n"
    [06:00:40][D][uart_debug:158]: <<< " / _ \\\\___ \\ _____\\ \\ /\\ / / | || |_ | |\r\n"
    [06:00:40][D][uart_debug:158]: <<< " | __/ ___) ||_____|\\ V V / | || _| | |\r\n"
    [06:00:40][D][uart_debug:158]: <<< " \\___||____/ \\_/\\_/ |_||_| |_|\r\n"
    [06:00:40][D][uart_debug:158]: <<< "\r\n"
    [06:00:40][D][uart_debug:158]: <<< " Inventek Systems\r\n"
    [06:00:40][D][uart_debug:158]: <<< " Embedding Connectivity Everywhere\r\n"
    [06:00:41][D][uart_debug:158]: <<< " Copyright (c)2011-2013\r\n"
    [06:00:41][D][uart_debug:158]: <<< "\r\n"
    [06:00:41][D][uart_debug:158]: <<< "> \r\n"
    [06:00:41][D][uart_debug:158]: <<< "C4:7F:51:01:D6:5F\r\n"
    [06:00:41][D][uart_debug:158]: <<<
    "ISM43362-M3G-L44,C2.4.0.3.AO7,v2.4.0,v1.4.0.rc1,v7.1.0,120000000,energySmart
    eS-WiFi FW-3.1\r\n"
    [06:00:41][D][uart_debug:158]: <<<
    "mySSID,myPASSWORD,3,1,0,192.168.0.12,255.255.255.0,192.168.0.5,255.255.255.255,255.255.255.255,2,1,0,US,1\r\n"
    couple stings omitted
    [06:02:45][D][uart_debug:158]: <<< "> \r\n"
    [06:02:45][D][uart_debug:158]: <<< "[TCP SSL] Connecting to 192.168.0.1\r\n"
    [06:02:45][D][uart_debug:158]: <<< "[TCP SSL] Validation Failure: 0C\r\n"
    [06:02:45][D][uart_debug:158]: <<< "[TCP SSL] Advanced context, failed to connect\r\n"
    [06:02:45][D][uart_debug:158]: <<< "ERROR: Unknown Error\r\n"
    [06:02:45][D][uart_debug:158]: <<< "Usage: P6 <0 = Stop, 1 = Start> \r\n"
    [06:02:45][D][uart_debug:158]: <<< "> \r\n"

    Luckily, there are smart people on the internet who figured it out: https://github.com/excaliburpartners/EnergySmartBridge. They provide a docker container, and everything is supposed to work from the get-go. Before you follow their instruction and build the container, read below. When they created their Docker config for the reverse proxy container, they used the nginx:latest image. The latest version then was 1.24. Now, the latest version is 1.27, which does not work anymore, so you have to go and edit their docker file in /energysmart-proxy: nginx:latest -> nginx:1.24. Then edit the config (both docker-compose.yml and EnergySmartBridge.ini) - give it the address of your MQTT broker, do docker-compose build, and docker-compose up -d. Ha, it's better now:
    Spoiler:
    [06:04:26][D][uart_debug:158]: <<< "[TCP SSL] Connecting to 192.168.0.1\r\n"
    couple stings omitted
    [06:04:27][D][uart_debug:158]: <<< "HTTP/1.1 200 OK\r\n"
    [06:04:27][D][uart_debug:158]: <<< "Server: Mono-HTTPAPI/1.0\r\n"
    [06:04:27][D][uart_debug:158]: <<< "Date: Fri, 07 Jun 2024 06:04:27 GMT\r\n"
    [06:04:27][D][uart_debug:158]: <<< "Content-Length: 15\r\n"
    [06:04:27][D][uart_debug:158]: <<< "Keep-Alive: timeout=15,max=100\r\n"
    [06:04:27][D][uart_debug:158]: <<< "\r\n"
    [06:04:27][D][uart_debug:158]: <<< "{\"Success\":\"0\"}\r\n"
    [06:04:27][D][uart_debug:158]: <<< "OK\r\n"

    The EnergySmartBridge service sends a couple of MQTT messages reporting the status of the heater controller. Nice, but very limited. This guy (https://github.com/starsoccer/energysmartbridge) extended the bridge and unified it with a reverse proxy. I couldn't get his reverse proxy to work, so I took his source code for the bridge only (https://github.com/starsoccer/energysmartbridge/tree/master/energysmartbridge/src) and copied it to EnergySmartBridge/EnergySmartBridge, which was created following the steps here https://github.com/excaliburpartners/EnergySmartBridge . Stop all the containers created by EnergySmartBridge, delete their images, repeat the build and start procedures (don't forget to update EnergySmartBridge.ini). Now, watch the UART logs. Once it connects, you should see new topics in the MQTT explorer, particularly the "homeassistant/water_heater/C47F5101D65F/config", where you can set the configuration. Primary it defines the "mode_command_topic": "energysmart/C47F5101D65F/mode_command", and the "modes": ["eco", "heat_pump", "electric", "off"]. You can either send things directly to this topic via mosquito, or you can create a climate entry in Home Assistant: (120C is actually 120F; when I set the heater to C, it behaves strangely - I will explore more)
    EnergySmart D65F water heater control interface displaying temperature and mode selection options.
    Now you can change the mode! Note that the dongle connects to the bridge only once every 5 minutes. So, if you change the mode in Home Assistant, don't rush to the heater to confirm; wait until the UART logs show another successful connection. Now plug it into an automation, and you're awesome! Now, you can disconnect the UART monitor.
    For those who are not willing to play with Docker containers and networks, there is an alternative, more hardware-oriented way. Read the comments section, too!

    * The protocol itself is RS485, but it's pretty useless without knowledge of how to decode the data. The dongle has an IC to decode it.
    ** I also played the router configuration to forcibly divert all traffic (especially requests to 8.8.8.8) from the dongle to 192.168.0.1. It turns out it is not necessary

    Cool? Ranking DIY
    About Author
    paulp
    Level 6  
    Offline 
    paulp wrote 9 posts with rating 14, helped 1 times. Been with us since 2023 year.
  • ADVERTISEMENT
📢 Listen (AI):

FAQ

TL;DR: If your A. O. Smith heat pump water heater is about 3x more efficient but the IRIS cloud died, “it’s alive”: you can repurpose a cheap Lowe’s IRIS dongle with local DNS, EnergySmartBridge, MQTT, and Home Assistant. This FAQ is for owners who want local mode control after the vendor shutdown. [#21110916]

Why it matters: It turns an abandoned cloud accessory into a local automation path that can switch a noisy hybrid water heater between heat-pump and electric modes on schedule. [#21110916]

Option Main parts Works locally Complexity Notes
Original IRIS cloud path IRIS dongle + energysmartwaterheater.com No Low Service was shut down
Self-hosted bridge path IRIS dongle + DNS redirect + Docker + MQTT Yes Medium Needs nginx pinned to 1.24
Hardware-oriented alternative Custom hardware approach Yes Medium–High Suggested for users avoiding Docker

Key insight: The practical breakthrough is not the UART tap alone. It is redirecting the dongle’s dead cloud hostname to a local bridge that speaks the expected HTTPS flow and publishes useful MQTT topics. [#21110916]

Quick Facts

  • The water heater’s remote port follows CEA 2045, and the post warns that the connector also exposes 240 V pins, so probing the wrong pins is hazardous. [#21110916]
  • The IRIS dongle board exposes UART test points near the Wi-Fi module: RX/TX on a 0.1-inch header, plus 3.3 V and GND on a separate 5-pin, 2 mm header. [#21110916]
  • The ESP32 logging setup used 115200 baud UART and showed the dongle booting an Inventek ISM43362-M3G-L44 Wi-Fi module. [#21110916]
  • The dongle does not poll continuously. It reconnects to the bridge only about every 5 minutes, which directly affects command latency in Home Assistant automations. [#21110916]
  • The working Home Assistant mode set exposed through MQTT is: eco, heat_pump, electric, and off. [#21110916]

How do you repurpose a Lowe's IRIS Energy Smart dongle to control an A. O. Smith heat pump water heater after energysmartwaterheater.com was shut down?

You repurpose it by replacing the dead cloud path with a local bridge. 1. Plug the IRIS dongle into the heater’s CEA 2045 port. 2. Redirect energysmartwaterheater.com to your local server, such as 192.168.0.1. 3. Run EnergySmartBridge with MQTT and control modes through Home Assistant or direct MQTT publishes. The post reports cheap used dongles on eBay and successful local control after the original Lowe’s service was sunset. [#21110916]

What is CEA 2045, and how does it work in a heat pump water heater remote-control port?

“CEA 2045 is a remote-control interface standard that lets appliances accept external control commands through a dedicated port, with a defined electrical connection and command framework.” In this heater, the port lets the IRIS dongle issue mode changes without modifying the main controller. The post also warns that this same port includes 240 V pins, so it is not a low-voltage hobby header. [#21110916]

What is RS485 in the context of the IRIS water heater dongle, and why isn’t the raw bus enough without the protocol decoder IC?

RS485 is only the electrical transport layer here, not the full command language. “RS485 is a serial physical-layer bus that carries differential data over wires, but it does not define the application protocol or payload meaning.” The post says the heater protocol rides on RS485, yet raw bus access is “pretty useless” unless you also know how to decode the data, which the dongle’s dedicated IC handles. [#21110916]

Where are the UART RX, TX, 3.3V, and GND pins on the IRIS dongle board, and how do you safely connect an ESP32 for logging?

RX and TX sit in two holes beside the Wi-Fi module on a usual 0.1-inch header, marked “1.” Power and ground are on a separate 5-pin, 2 mm header, marked “2,” with pin 3 as 3.3 V and pin 4 as GND. The post used an ESP32 as a UART adapter at 115200 baud. Use only 3.3 V logic, and do not probe the heater’s 240 V CEA 2045 pins casually. [#21110916]

Why does the IRIS dongle show a TCP SSL validation failure when redirected to a local bridge, and how do you fix it?

It fails because the dongle still expects a valid HTTPS session when you redirect the hostname locally. The UART log shows: “[TCP SSL] Validation Failure: 0C” after connecting to 192.168.0.1. The fix is to use the EnergySmartBridge setup that reproduces the expected reverse-proxy behavior rather than serving a simple local endpoint. After the bridge was corrected, the log changed to “HTTP/1.1 200 OK.” [#21110916]

How do you use Pi-hole or local DNS to redirect energysmartwaterheater.com to a self-hosted EnergySmartBridge server?

Create a local DNS A record for energysmartwaterheater.com and point it to the bridge host. The post used Pi-hole, but any DNS server can do it, with 192.168.0.1 given as an example bridge address. The author also tested forced router redirection, including requests toward 8.8.8.8, then concluded it was unnecessary once DNS redirection worked. [#21110916]

Which nginx version works with the excaliburpartners EnergySmartBridge Docker setup, and why does nginx:latest break it now?

nginx 1.24 works, while nginx:latest broke because it now resolves to 1.27. The fix was to edit the reverse-proxy container definition from nginx:latest to nginx:1.24 before rebuilding. The post states the Docker setup originally worked when “latest” meant 1.24, but no longer worked once “latest” advanced to 1.27. [#21110916]

What changes do you need to make in docker-compose.yml and EnergySmartBridge.ini to get the IRIS dongle talking to MQTT?

You need to point both files at your MQTT broker and then rebuild the containers. The post says to edit docker-compose.yml and EnergySmartBridge.ini, set the broker address, then run build and start again. Once that was done, the bridge returned HTTP 200 to the dongle and began publishing status messages into MQTT. [#21110916]

How do you merge the starsoccer energysmartbridge source with the original EnergySmartBridge project to expose more Home Assistant and MQTT controls?

Use the original project as the working base, then replace only the bridge source. 1. Build the excaliburpartners EnergySmartBridge project first. 2. Copy the starsoccer energysmartbridge source tree into EnergySmartBridge/EnergySmartBridge. 3. Stop containers, delete images, rebuild, and restart after updating EnergySmartBridge.ini. The result exposed richer MQTT topics, including a Home Assistant discovery config topic for the heater. [#21110916]

Why does the IRIS dongle only check in about every five minutes, and how does that affect Home Assistant automation timing?

It checks in on a roughly 5-minute interval because the dongle only connects back to the bridge periodically, not continuously. That means mode changes from Home Assistant do not apply instantly. The post warns not to rush to the heater after sending a command; wait until the next successful UART-visible connection before verifying the new mode. [#21110916]

How do you publish mode changes like eco, heat_pump, electric, and off to the energysmart MQTT topics for this water heater?

Publish the desired mode string to the bridge’s mode command topic. The discovered Home Assistant config exposed mode_command_topic as energysmart/C47F5101D65F/mode_command and listed four valid modes: eco, heat_pump, electric, and off. The post says you can send those values directly with mosquitto or let Home Assistant publish them through its water-heater entity. [#21110916]

What is the difference between the original excaliburpartners EnergySmartBridge and the starsoccer fork for A. O. Smith water heater integration?

The original bridge worked but exposed only limited heater status and control. The starsoccer code extended the bridge and unified it with a reverse proxy, giving more MQTT and Home Assistant-friendly controls. The author could not get that reverse proxy working as provided, so they copied only the bridge source into the original project and kept the original container approach. [#21110916]

Why does setting the heater to Celsius behave strangely when the Home Assistant integration appears to treat 120C like 120F?

The post suggests a unit-mapping bug or mismatch in the exposed control path. The author states that “120C is actually 120F” in the integration view and says the heater behaves strangely when set to Celsius. No full fix is given, so the safe conclusion is that Fahrenheit values map more predictably in this setup and Celsius needs more investigation. [#21110916]

What safety precautions matter when working with the CEA 2045 port on a water heater that exposes 240V pins?

Treat the port as mains-adjacent hardware, not as a safe logic connector. The post explicitly warns that the CEA 2045 port includes 240 V pins, and it also notes that some header pins show 3.3 V yet are not connected to the Wi-Fi module VCC. Use a 3.3 V UART only on verified pins, avoid exploratory probing, and disconnect power if you are unsure. [#21110916]

What hardware-based alternatives exist if you don’t want to use Docker, reverse proxies, and MQTT to automate an A. O. Smith heat pump water heater?

A more hardware-oriented alternative exists and may suit users who dislike container stacks. The post links to an Instructables method for A. O. Smith heater monitoring and specifically recommends reading the comments too. That path avoids the local HTTPS bridge workflow, though the author presents it as an alternative rather than the main method used here. [#21110916]
Generated by the language model.
ADVERTISEMENT