Navien, ESP32 Navilink interface

NCB 240/110H combi unit installed here, mostly the same protocol, but the starting bytes are f7 06 instead of f7 05. @htumanyan (Likely) CRC checksum calculation and seed remains the same.

I’m trying to figure out the hotbutton serial data to send, but don’t have a navilink to capture the data. It doesn’t respond to the hotbutton press/release commands above starting with 0xf7 0x05. It also doesn’t respond to the hotbutton commands with a 0xf7 0x06 prefix and a recalculated checksum.

Example Incoming Packet:
[15:02:04][I][Navien:211]: f7 06 50 0f 90 2a 45 00 0d 01 0a 06 0e 83 5a 33 2e 4d 46 9e 00 21 00 00 7b 43 00 00 5f 01 70 05 00 00 00 00 25 01 a7 04 9a 06 78 3c a4 50 00 00 36

There are still just two packets.

        switch (serialBuffer[3]){
          case 0x50:
                                          
            PowerState.publish_state(serialBuffer[9]); 
            WaterFlow.publish_state(serialBuffer[18]/10.0*0.2642); // GPM
            SysStatus.publish_state(serialBuffer[24]); 
            break;                        
          case 0x0F:
            ESP_LOGI("Navien", "%s", buffer);
            HTSetpoint.publish_state(serialBuffer[13]/2.0);
            DHWSetpoint.publish_state(serialBuffer[14]/2.0);
            DHWOutlet.publish_state(serialBuffer[15]/2.0); 
            DHWInlet.publish_state(serialBuffer[16]/2.0); 
            HTTempSupply.publish_state(serialBuffer[17]/2.0); 
            HTTempReturn.publish_state(serialBuffer[18]/2.0); 
            gasUsageBytes.b1 = serialBuffer[22]; // low byte
            gasUsageBytes.b2 = serialBuffer[23]; // high byte
            GasUsage.publish_state(gasUsageBytes.us1);
            GasTotal.publish_state(serialBuffer[24]/10.0);
            break;
        }

Awesome work everyone! Is there one repo where I can find the cumulative updates?

I don’t know much about 485 serial comms so can’t help with that part of the code but will if I see any opportunity to do so.

Did you get yours working based on your diagram? I have a NPE-240A and I can’t find 12v on the pins. Seems some pins are showing 5v and 3v. Using another power source, I don’t seem to get any serial data from the pins either.

Any pointers would be great.

1 Like

I have not. Have not had time due to work. Plus I have not installed the water heater yet, due to work load also and cold weather setting in. Though I could probably test it without being installed. Not sure if that would screw with anything.

It is going to heat my floors also. Plus I plan on retro-fititng my HVAC with a coil to heat the house. Already retro-fitted my floor themostat and monitoring system using a Shelly UNI.

Thanks for the quick response. I’m still struggling trying to get any receive data. I must be missing something as I believe I have the correct pins connected to the RS-485 module. I started with [
tsquared96’s yaml for the ESP32. I tried swapping enabling debugging and swapping between rx0/tx0 to rx2/tx2 on the ESP32, but not joy. I don’t see any debug level data as I expected. If anyone has ideas where I’m going wrong, feel free to chime in.

@smurf12345 I’m curious - What ESP board are you using? I know sometimes I think I have the right pinout for my board, yet I look another place and find that the pinout is different? It is certainly frustrating. Also, maybe posting your yaml might steer someone to help you further? Possibly even a drawing, or photo of your project could help too?

Cheers!

Todd

Blockquote

Hi @tsquared tsquared:
I’m using a ESP32-WROOM-32 and a TTL to RS485 from amazon. I’ve connected it as pictured below. I used your yaml config from github with the below. I’ve also tried tx0/rx0 using tx-pin:1 and rx-pin:3. When I flip the home-assistant switch to turn on the water heater, I do see the tx led light up on the rs-485 module. I never see rx led light up.

When probing around the 5 pin connector on the panel, I don’t see 12v on pin 1. So I’m powering the ESP via usb for now. Pins 2 and 3 I see some where between 2-4volts. Pin 4 I believe was 5v.

My assumption is with the log level set to debug, I’d see some data come through, but it is silent.

substitutions:
  comment: "Water Heater"
  friendly_name: Water Heater
  logger_level: DEBUG

# Enable logging
logger:
  level: ${logger_level}
  baud_rate: 0 #disable logging over uart

#################################
#### UART SETUP/DECODE BYTES ####
#################################

uart:
  id: uart_bus
  tx_pin: 17
  rx_pin: 16
  baud_rate: 19200
  data_bits: 8
  stop_bits: 1
  parity: NONE
  debug:
    direction: BOTH
    dummy_receiver: True
    after:
      delimiter: "\n"
    sequence:
      - lambda: |-
          // Log all received data
          UARTDebug::log_string(direction, bytes);

<cut the rest of the yaml from your posted github yaml>
1 Like

Well, I’m an idiot. I didn’t enable the connection mode in the Navien connection settings and set the “NaviLink connection enabled (ON)”. I don’t have a Navilink so I never knew it needed to be enabled. Now data is streaming in… :grinning:

Now to figure out why it’s not recognizing the data… and sensors se

[16:06:55][D][uart_debug:158]: <<< "\x04}\x17\xFD\xFD\xD9\xF9\xCB\xFF1\x9F\xA5\xFF\xFF\xFF\xFF\xFD\xF0\xFFS\xFF\xFF\xB9\xE9a\x9B\vc\x05\xFF\xBE\xFF\xFF\xFF[\xFF\xFF\xFFo"
[16:06:56][D][uart_debug:158]: <<< "\x04}\xF5\xF5\xB3\xB3\xFD\xFF\xF5\xAE\x9F\xA5\xFF\xFF\xFF\xFF\xFF\xFF\x8F\xFF\xFE\xFF\xFF\xBE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
[16:06:56][D][uart_debug:158]: <<< "\x04}\x17\xFD\xFD\xD9\xF9\xCB\xFF\x9F\xA5\xFF\xFE\xFF\xFF\xFD\xFE\xFFS\xFF\xFF\xB9\xA4a\x9B\v\x05\xFF\xBE\xFF\xFF\xFF[\xFF\xFC\xFF"
[16:06:56][D][uart_debug:158]: <<< "\x04}\xE5\xF5\xB3\xDB\xFD\xFF\xF5\xD7\x9F\xA5\xFF\xFF\xFF\xFF\xFC\xFF\x0F\xBF\xFF\xFF\xFE\xFF\xBE\xFF\xFF\xFC\xFF\xFF\xFF\xFE\xFF\xFF"
[16:06:56][D][uart_debug:158]: <<< "\x04}\xD7\xFD\xFD\xD9\xF9\xCB\xFF1\x9F\xA5\xFF\xFF\xFE\xF8\xFD\xFF\xFFS\xFF\xFF\xB9\xE9a\x9B\vc\xF8\xBE\xFF\xFF\xFF[\xFC\xFE\xFFo"
[16:06:56][D][uart_debug:158]: <<< "}\xC5\xF5\xB3\xDB\xFD\xFF\xF5\xD71\x9F\xA5\xFF\xFF\xFF\xFF\xF0\xFF\x8F\xBF\xFF\xFF\xFF\xFF\xBE\xFF\xFF\xF0\xFF\xFF\xFF\xFF\xFF\xFF"
[16:06:57][D][uart_debug:158]: <<< "\x04}\xD7\xFD\xFD\xD9\xF9\xCB\xFF1\x9F\xA5\xFF\xFF\xFF\xFF\xFA\xFE\xFFS\xFF\xFF\xB9\xE9a\x9B\vc\xFF\xBE\xFF\xFF\xFF[\xFF\xFF\xFFo"
[16:06:57][D][uart_debug:158]: <<< "\x04}\xE5\xF5\xB3\xDB\xFD\xFF\xF5\xAE1\x9F\xA5\xFE\xFF\xFF\xFF\xFC\xFF\x8F\xBF\xFF\xFE\xFF\xFF\xBE\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF"
[16:06:57][D][sensor:094]: 'Total Gas Use CCF': Sending state nan CCF with 1 decimals of accuracy
1 Like

Now it is working. For those that never had a navilink and going the RS-485 route, make sure to enable the “NaviLink connection enabled (ON)” in the control panel.

For NPE Models: You can configure the NaviLink connection setting mode on the front panel of NPE water heaters connected to the NaviLink.
1. On the front panel, press the Power button to turn off the water heater.
2. Enter the R&D information menu by pressing the Up (+) button three times, the Down (-) button three times, and then the Up (+) button four more times.
3. Use the Up (+) or Down (-) buttons to move to “2.PAR” (Parameter information mode), and then press the Info button. Display Description Technical information Parameter information
4. In the Parameter information time mode, use the Up (+) or Down (-) buttons to select “P.18”. Then, press the Info button to enter the NaviLink connection setting mode.
5. In the NaviLink connection setting mode, use the Up (+) or Down (-) buttons to change the value and press the Info button to set to the desired mode

1 Like

@smurf12345 Awesome! Glad you got it working. Although I never had a navilink, I do not recall having to perform the procedure you refer to above. This is however GREAT information for those that follow this path after us! :smile: Thank you for posting this writeup!

Hi, is this compatible with Navien Deluxe-C (comfort) model?

@smurf12345 I also have the 240A with a ESP Wroom 32, but I can’t get it working. I enabled the navlink connection on the water heater, but the esp32 still not not logging data. Would you mind sharing your final connection diagram? Did you tx2 and Rx2 pins the on the esp32? I was powering the esp32 separate with a 5v for testing. Thanks!

I used the tx2/rx2 pins as I read that tx/rx may be tied to some boot process. But I think it would work either way. On my ESP32, tx2/rx2 are pings 17 and 16. That was the only adjustment from tsquared’s github yaml. Over Christmas break, I may try to convert to use the power from the navient to power the ESP with a dc-dc buck converter, but for now just a normal usb wall wart works.

uart:
  id: uart_bus
  tx_pin: 17
  rx_pin: 16
  baud_rate: 19200
  data_bits: 8
  stop_bits: 1
  parity: NONE

1 Like

BTW, after some more debugging I’ve found that when the packet is sent from control device to Navien, the CRC needs to be calculated with 0x62 seed value as opposed to 0x4B that is used for packets coming out of navien. See Navien::parse_packet() in navien/esphome/navien/navien.cpp at dc047a546a4595fd5dc565b4176343f6c07507a8 · htumanyan/navien · GitHub

2 Likes

Hey everyone!
Thanks to some extra free time over the holidays, I finally had the opportunity to dedicate more time to this project and made some meaningful progress.

I’ve managed to create an ESPHome module for Navien tankless heaters. This module brings together everything I’ve learned from my traces and the invaluable insights I’ve gained from this amazing community. Right now, it supports all the “read” capabilities, though there are still a few fields left to decode.

The next step is to enable write capabilities – like setting the temperature, activating the hot button, and more.

The source code and build instructions are in the same Git project navien/esphome at dc047a546a4595fd5dc565b4176343f6c07507a8 · htumanyan/navien · GitHub
I’d love any feedback, contributions, pull requests or suggestions…

I’m really excited about how far this has come, and I’m even more excited about where it’s headed. Huge thanks to everyone here for your shared knowledge and support – this progress wouldn’t have been possible without you.

1 Like

I confirmed that 0x62 works to calculate the checksum on all the command packets I have decoded via some quick unit tests.
that’s going to be useful for actually implementing set-temp commands

  f7 05 0f 50 10 0c 4f 00 0b 00 00 00 00 00 00 00 00 00 0a : off
  f7 05 0f 50 10 0c 4f 00 0a 00 00 00 00 00 00 00 00 00 ce : on
  f7 05 0f 50 10 0c 4f 00 00 74 00 00 00 00 00 00 00 00 ea : set to 58c
  f7 05 0f 50 10 0c 4f 00 00 72 00 00 00 00 00 00 00 00 c4 : set to 57c
  f7 05 0f 50 10 0c 4f 00 00 00 00 01 00 00 00 00 00 00 6a : hotbutton press
  f7 05 0f 50 10 0c 4f 00 00 00 00 00 00 00 00 00 00 00 2a : hotbutton release
  F7,05,0F,50,10,0C,4F,00,00,00,00,10,DF,00,00,00,00,00,3E : recirculation off from app
  F7,05,0F,50,10,0C,4F,00,00,00,00,00,DF,00,00,00,00,00,D4 : recirc off ack?
  F7,05,0F,50,10,0C,4F,00,00,00,00,08,D9,00,00,00,00,00,D0 : recirculation on from app
  F7,05,0F,50,10,0C,4F,00,00,00,00,00,D9,00,00,00,00,00,14 : recirc on ack?

Note that when I send a recirc command from the app, it seems i get an acknowledge response back that looks very similar.

Theres still a lot of bytes undocumented in the read data, but even the navien app doesn’t expose all of them.
I’ve posted before, but I’ve done my best to document data I have found on my device here ESPHome-Navien/navien.yaml at 9cd4e032d7bce93334985430a40ee6ceb56e4588 · evanjarrett/ESPHome-Navien · GitHub

1 Like

Hi everyone, I have been trying out this over the last couple of days. Thanks everyone for the huge research into the protocol.

I have a 240A Navien unit. Like @smurf12345, I don’t see +12v power on Pin 1, and I am powering my ESP32 externally. I have a navilink unit, though it is not the stand alone unit, it is the unit that has a separate power supply and multiple ports. I would love to power it from the hot water unit, as I found this RS-485 HAT that is all-in-one for my Wemos boards.
@smurf12345 were you able to find the 12v pins?

Initially I was getting random data, but when I reversed my +A/-B RS-485, it started working.

While looking through the data, I decoded one more field. In the Gas packet, the total operating time (hrs):
id(uart_gas_byte35).publish_state(bytes[35]); // total_operating_time_lo
id(uart_gas_byte36).publish_state(bytes[36]); // total_operating_time_hi

I am confused why the water data and the gas data both contain Set Temp, Outlet Temp and Inlet Temp. When I have been monitoring the data, they are not always the same, but they are always close. Are they different sensors?

Yes, I’ve noticed the same - values are close but not the same. My guess is that the data comes from different sensors that are located closely along the water/gas path. The navien app though, displays the temperature from the gas packet, not the water.

1 Like

In addition to enabling NaviLink on my unit, I also had DIP switches that were misconfigured. Until I changed them, I saw no data coming from my unit (240A).

For reference, here’s an image of the page in manual identifying the necessary DIP config (saved from another forum post):

On my unit, DIP SWITCH 1-2 had #4 set ON, which doesn’t match up to any valid configurations. After ensuring switch positions matched with the reference image I was seeing data coming through, however, Home Assistant sensors did not populate. Some more troubleshooting led me to same as @dacarson

Initially I was getting random data, but when I reversed my +A/-B RS-485, it started working.

I also experienced this with a 240A (was converted to Gas via kit by previous owner). I initially hooked up same as smurf12345, but sensors didn’t populate until I swapped +A/-B. I also did not find 12V on the expected pins of the KDC330F panel, though I have an outlet very close so it is not a big priority for now.

I’m looking forward to doing some more testing, especially with upcoming “Set” capabilities such as HotButton.

One more. In the Water packet, the Operating Capacity is:
id(uart_water_byte17).publish_state(bytes[17] / 10.0 / 2.0); // Sort of looks like GPM Operating Capacity (0 - 100%)

I’ve investigating:
id(uart_water_byte8).publish_state(bytes[8]); // 0, 8, 32 related to recirc running
What I have seen is that when water is flowing but it is not heating, it has a value of 3. With the water still flowing and heating turns on (ie current gas > 0), it goes back to 0.