Navien Hot Water heater - Navilink

It’s not compatible with Navilink 128 (at least the version I have), even the HA “official” Cozytouch integration (Overkiz) isn’t.

I made a custom integration for Cozytouch that works with my Navilink 128 + Naema Micro 25, you can try it if you want : GitHub - gduteil/cozytouch: Atlantic Cozytouch integration for Home Assistant

1 Like

Thanks!
what sensors are available?

It depends on your device, and some adjustments need to be done if your device has not been integrated yet.
What device are you using ?

Lot of sensors and controls are available in the Cozytouch API, at least everything you can have in the official app will be accessible in the integration, but much more sensors are published and not used by the app.

I have an NPE-240A2 and I just ordered a NaviLink Lite. I also have a logic analyzer as well as a capable digital storage oscilloscope. I think I am going to set things up initially using this integration, but for fun I also think I am going to have a go at examining the RS-485 traffic. I’ll let you know what I find out :grinning:.

oh - can you say more about examining the RS-485 traffic? i have another device i want to do that on. i have a couple of USB to RS-485 connectors but haven’t used them yet, haven’t figured out where to start actually. that’s the next rabbit hole i’m going down :joy:

I have an NPE-210S, and bought the 5 pin to RJ-45 Navien cable. Then - using an RJ45 breakout connector. I measured with my DVM each one to ground, and found that there were 2 lines that were around 2.5-3VDC, and one line that was 12VDC. So, I think that the 5 pin connector (which only has 4 wires attached) actually is 2 RS-485 wires, 1 - Power, and 1 Ground wire. Then, I took a bit of time over the last few days to analyze the signal using my logic analyzer. I think I finally got it to read the signals without any framing errors. Additionally - I think it’s right as I see quite a bit more data when the unit is running and producing hot water than I do when it is idle.

It looks like the comm specs are 19200, 8, NONE,1 It seems that RS485-A is MSB-first, and Inverted. and RS485-B is MSB-first, and NOT Inverted.

My end goal here would be to utilize ESPHOME to interface with this unit and be able to read the data that is being transmitted on these communication lines. Maybe even using the 12VDC from the unit to power the ESP?

Now for the part that might be a bit over my head – using the decoder to interpret the data. Thoughts on where/How to start?

RS-485 is really just standard serial / UART at the protocol level. It’s a little different at the physical level in that it is a differential set of wires to help reject noise and make it more reliable in harsh noisy environments. (So, instead of say 3 wires - gnd, tx, rx there will be five wires - gnd, rx-, rx+, tx-, tx+) (this is assuming separate rx/tx). RS-485 can also operate at higher differential voltages, again to support better high-noise communication (higher signal-to-noise-ratio).

In any case - I just got the Lite unit hooked up to my water heater today. I’ll get to some data sniffing in the next few days hopefully!

1 Like

@mbcomer - Awesome News that someone else is going down this road too! Glad to hear you have a Lite unit all hooked up and something to sniff the data lines from. I have been trying different things here - and struggling a bit to understand your statement above regarding the 5 wire’s vs what I thought I knew about RS-485 (I thought the RS422 was 5 wire?). As I noted above, the cable only has 4 wires of the 8 in the RJ-45 connector. This was verified and continuity tested. If my DVM was correct, it seems that I have 12VDC, GND, TX+, and TX- for the communications. I’m curious, does the Navilink Lite get power from the RJ-45 or does it need it’s own power connector? If so, that likely explains the 12VDC. Based on this video, it seems I have a different connector. My connector only has 4 wires. I went and put jumpers on all 5 pins in that connector (directly on the board) - the 5th place in that connector does not appear to have any signal/voltage on it. Anyway, here is a snip of what I see from the logic analyzer on just the raw data being transmitted from the unit. At the time of the screenshot I had disconnected the 12VDC - as it didn’t seem necessary to monitor any longer. Also, it appears that either have quite a bit of noise on one of the lines. I have read 120ohm resistor could help that? You can see it to the left of the RS-485B signal line near the beginning of the screenshot.

Then, I setup the decoding. Either I don’t understand what it is telling me or I have something setup wrong on the decoding front. Thoughts here are welcomed! I do see that I get some framing errors at first (within the first few bits) but they go away after that. I have read in a few other places - where RS-485 requires some “math” to get the right data as it is a differential protocol. It does seem that the wave forms from the first capture are just that - inverted from each other.

Appreciate any further direction from this information, and insight into where to turn next.

1 Like

If they were similar in price, is it better to get Navi Link or Navi Link Lite?

depends how many Navien water heaters you have. If you have one, then get the Navi-Link Lite.

Thanks, I ordered the Lite version. I’m so looking forward to make water heating smarter :smile: Getting stats is the first step.

Ultimately I want to make the hot button recirc intelligent , like described here:

I built an RS485 sniffer similar to this one: RS485 sniffer

I used the UART settings @tsquared provided (19200, 8N1) (thanks!), and connected the sniffer to a tap on the cat5 cable provided with a Navilink lite. Using this cable, the blue and blue-white wires appear to be the RS485 signals. I connected blue to RS485-B and blue-white to RS485-A.

With no navilink attached, the water heater continuously emits two alternating packets (with a short interval between each). I believe each of them contains continuous status information. Let’s call them A and B. With a navilink connected, the navilink sends an announcement packet (let’s call it C) after each packet from the heater. The result is a stream that looks like: A C B C A C B C…

There is a fourth type of packet when the navilink sends a command. It appears the navilink simply repeats the command several times (typically 6), with no acknowledgement from the heater.

I observed the packets while performing various operations, and I believe I have decoded most of the data and commands available in the navilink app. Here are the packet captures and what I have identified so far.

Common Fields

The first 6 bytes appear to be a packet header. The first two bytes are common to all packets. The next three uniquely identify each of our three packet types. Byte index 5 is the length of the data, not including the header (6 bytes) or the final byte, which I believe is a checksum. In other words, byte index 5 is the length of the packet minus 7 bytes.

Index Value Notes
0 f7 Common to all packets
1 05 Common to all packets
2 Packet id byte 0
3 Packet id byte 1
4 Packet id byte 2
5 Data length
Data
N Checksum

Packet A (from heater)

This packet seems to have information related to water.

Here is a full example packet:

f7 05 50 50 90 22 42 00 00 05 14 72 37 2e 00 00 00 00 00 00 f8 8e 00 00 02 00 00 00 05 00 07 00 00 02 00 00 00 00 00 00 67

And the fields decoded so far:

Index Value Notes
0 f7 Common to all packets
1 05 Common to all packets
2 50 Packet id byte 0
3 50 Packet id byte 1
4 90 Packet id byte 2
5 22 Data length
09 05 System power: high nibble: unknown (values 0 and 0x20 observed); low nibble: 0=off 0x5=on
11 72 Set temp - measured in 0.5 degrees C. 57C in this case
12 37 Outlet temp - measured in 0.5 degrees C. 27.5C in this case
13 2e Unconfirmed, but possibly inlet temperature? This seems very close to the inlet temperature, but was usually off by 0.5-1.5C. My inlet temperature did not vary enough to analyze more
18 00 Unknown, but appeared proportional to water flow rate
19 00 Flow rate - measured in 0.1 liters per minute (divide by 10 to get LPM)
24 02 System status. Probably a bitwise field. Partially decoded: display units: 0x08 position: 1=metric 0=imperial. 0x02 position: 1=weekly 0=hotbutton

Packet B (from heater)

This packet seems to have information related to gas.

Here is a full example packet:

f7 05 50 0f 90 2a 45 00 0b 01 0c 03 17 00 72 6d 23 00 00 00 00 00 00 00 61 00 00 00 0b 00 1d 00 f6 34 00 00 05 00 00 00 00 00 aa 48 00 00 01 00 b3

And the fields decoded so far:

Index Value Notes
0 f7 Common to all packets
1 05 Common to all packets
2 50 Packet id byte 0
3 0f Packet id byte 1
4 90 Packet id byte 2
5 2a Data length
22 00 Low byte current gas usage in kcal
23 00 High byte current gas usage in kcal
24 61 Total gas usage in 0.1m^3 (divide by 10 to get m^3; 9.7 cubic meters in this case)

Packet C (from navilink)

This appears to be an announcement packet. It tells the heater there is a navilink attached. The heater uses this to disable local setting of the weekly schedule and instead require setting the schedule from the app.

Here is a full example packet:

f7 05 0f 50 10 03 4a 00 01 55

Packet D (from navilink)

This is the command packet. I tested each of the following commands: power off, power on, set temp, hotbutton. Each type of command uses a different field. I only ever saw a single field used since I tested it using the navilink app, but the format suggests that more than one command could be combined into a single packet. The navilink repeats the on/off/set commands 6 times. For hotbutton presses, it sends the on command twice followed by the off command once.

Here is a full example:

f7 05 0f 50 10 0c 4f 00 0b 00 00 00 00 00 00 00 00 00 0a

Index Value Notes
0 f7 Common to all packets
1 05 Common to all packets
2 0f Packet id byte 0
3 50 Packet id byte 1
4 10 Packet id byte 2
5 0c Data length
8 0b Power: 0x0a=on 0x0b=off
9 00 Set temperature (units of 0.5C: 0x74 is 58C)
11 00 Hotbutton: 0x01=press 0x00=release

Here are all the commands I have seen as full packets (so you can see the checksums):

  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 58
  f7 05 0f 50 10 0c 4f 00 00 72 00 00 00 00 00 00 00 00 c4 : set to 57
  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

Checksum

I believe the final byte is a checksum, but I have not identified the algorithm yet. It would be useful to do so for the commands (especially the temperature set commands).

2 Likes

the easiest option for me was having the bathroom light switch trigger the hot button.

So far this project has been very interesting. I am learning at every turn! This is great information! Thank You @suva! I took what you had, and tried with my limited python skills to pull it into python directly using a RS485/USB adapter. Also, built an ESPHome UART Sniffer as you describe above. In both cases - essentially, It reads the information you show above!! I am now trying to figure out how to manipulate the data to get the respective bits/bytes/strings out of this information.

This brings me to my next question - although you note, and I can see the f7 05 common data for all, the data streamed from the COM port starts long before I can see those values.

For example: The raw stream looks like this - (I **'d the f7 05 for clarity - it shows up 2x in this example.)

b'\xd8\xbc\x1a\x00\xb0\x02\x00\x00\x00\x00\xa6I\x00\x00\x00\x00\xb9\**xf7\x05PP**\x90"B\x00\x00\x05\x14x0*\x00\x00\x00\x00\x00\x00\x00\xaf\x00\x18\x00\x00\x00\x00\xb0\x02\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\xbb**\xf7\x05P**\x0f\x90*E\x00\x01\x01\x14\x07"\x00x0\x1b\x00\x00\x00\x00\x01\x00\x00\x9f\x1f\x00\x00\xd1\x03Z\n'

Interesting enough - that data stream also shows some weird values like the P or PP next to the 05 among other oddities. I have been able to convert it directly to a hex stream and received the following results which appear more accurate:

0xd8bc1a00b00200000000a64900000000b9f70550509022420000051478302a00000000000000af001800000000b00200000002000000000000bbf705500f902a450001011407220078301b000000000100009f1f0000d1035a0a

It seems like I should be able to slice the hex data stream better than the raw one as it appears more accurate? I am grateful for all the help!

Anyone on Next thoughts on python libraries, or ESPHome coding that helps break this down into a useable format?

I did find this post, but it doesn’t seem “solved”. It links to this post, which talks about custom devices in ESPHome, which currently appears past my abilities. I guess I’m back to the reading and learning phase!

Ok - I worked my way through some really crude python and I have it displaying some information regarding the water, and printing to the REPL. Now that I can actually read it for what data it is supposed to be showing, It appears that I may have some differences from what @suva shows.

As it relates to index 18 & 19 (flow) on the water side. It seems that my water flow is actually index 18, as index 19 never changes for me. Index 19 is always zero. I confirmed that the front panel shows the value I am calculating on index 18 in the code, back to GPM.

Also, index 13 - that value seems strange to be inlet temperature. Guess I will have to keep watching and comparing that value to the front panel of the unit and see what it says.

I got my module today. Navilink Lite is using STM32F412 for MCU and MXCHIP EMC3280-E for WIFI.