@tsquared I would ask a mod to most post x (fill in) down to the last into a new thread in the esphome section.
The GPIO of the esp32 is 3.3V and only 5V tolerant so whole it works it would be better to use a rs485 to 3.3V board. I will look for one and report back. I will also dig into digikey / mouser to see if I can pinpoint that connector. Do you see any numbers or letters marked on the connector?
Edit: Could it be this one - VHR-5N JST Sales America Inc. | Connectors, Interconnects | DigiKey
tsquared
(Todd)
April 23, 2024, 4:44pm
35
Apologies in advance, I don’t know how/who to ask to move the topic, and unfortunately created a post in the ESPHome category before I realized that @aruffell posted that this could be moved. Do you just @ a moderator and they should see it?
If it does move, it probably should begin starting with the post below.
https://community.home-assistant.io/t/navien-hot-water-heater-navilink/330044/87?u=tsquared
The ESPHome category post is here for combining/changing etc.
I have a Navien Hot Water Heater, that uses RS-485 to communicate. What I am trying to build is an ESP32 Interface for this unit, and have quite a bit of it working. I am hoping to find that help here and allow me to finish out the last few items that will make this complete!. In a thread here , contains most of the details.
Below is my current Configuration and a snip from the subsequent web page it produces.
I am confident there are better/more efficient ways to produce this, but with my basi…
Please let me know if I need to do something else.
Thank you all for your help here! Certainly appreciated!
Also, @aruffell Awesome find here! The connector you show certainly looks like the one I have. Do they usually come with any of the internal pins that you would need to connect the wires? Or can you get them with wires attached.
Could you post pinout of that connector? Which one is 12VDC, which are RS485 and ground pins.
I am thinking of using this RS485 base and add this controller to it. It seems that in that case it can directly power controller from 12VDC input of RS485 and looks neat. They also have RS485 in other forms for other controllers, also with 12-24VDC input to power controller.
Connector does not look like JST VH one. Here is the spec for VH connector . Note how bumps are on the outside edge while Navien connector has bumps little closer to the center of connector.
tsquared
(Todd)
April 23, 2024, 8:50pm
38
I realize now what you were saying about the 5vdc scenario. I remembered, I purchased this adapter instead. This is actually what is in the circuit now.
The link to this device is here .
I will update the original post to reflect this difference.
1 Like
tsquared
(Todd)
April 23, 2024, 9:18pm
39
Here is the pinout I have.
1 Like
@kkopachev - true, not the one. How about the JST XHB?
I can’t find dimensional drawings, but this picture looks really similar. I need to measure the pitch of the actual connector… that would help narrow down the search.
1 Like
@tsquared - your post about where to clip the thread so it can be moved to your other post that is in the esphome section seems to reference only that other thread. If you can correct that there is a chance @tom_l can fix it for is.
tsquared
(Todd)
April 24, 2024, 2:09am
42
@aruffell Good catch! Apparently too much copying and pasting lately! Thanks for the heads up. It has been modified to reflect the correct link.
@tsquared - I believe the two threads were merged. The order may be out of sequence, not sure, but at least it is all here.
brystmar
(Thomas)
May 15, 2024, 4:07pm
44
Posts are definitely out of order. I wonder if the admins can can re-index them by date? Gonna flag this thread to bring it to their attention.
1 Like
brystmar
(Thomas)
May 15, 2024, 4:56pm
45
Appreciate the direct links to those controllers! I love how this RS485 controller steps down voltage to 5v for the ESP. Just ordered mine, will arrive in a few weeks.
I’m eyeing these JST XHB connectors on aliexpress. Going with XHB over the XH to ensure a nice secure fit. Can always snip off the latching tab anyway. Likely ordering the 5-pin model in 300mm length, since I’d much rather cut & re-strip than try extending short wires.
Are we handling enough current here that wire gauge matters? Options are 22, 24, and 26awg. Will probably get the 22 since it’s better to err on the side of thicker wire.
Edit to answer my own question about wire gauges and current. This wire gauge chart outlines the maximum amperage for power transmission by gauge:
Gauge
Max Amps
22 awg
920 mA
24 awg
577 mA
26 awg
361 mA
ESP32 needs 5v @ 500mA, so the 26awg could overheat and melt. 24awg should work, but it’s probably best to spend an extra $0.27 on the 22awg. Ordering now
@kkopachev - Nice solution! I was looking at the compatible Atom controllers and the gray one is the one to go with for me as it can operate up to 60C, while the white Atom S3 Lite only reaches 40C. My attic easily exceeds 40C in the summer.
Based on posts above, it appears the Navien can supply 12V, not 5V. How are you powering the Atom? Did you add a 12V to 5V buck converter?
Edit: Never mind, I just noticed the RS485 part does the 12V to 5V
brystmar:
ESP32 needs 5v @ 500mA
But supplied voltage is 12v from the heater, so less current. I guess any gauge can work
Has anyone created a Grafana Dashboard and docker container for all this yet?
@kkopachev - Would you mind sharing the yaml for the M5Stack RS485 base and the Atom? I purchased the same hardware. Thanks!
I am using one posted above, just with slight changes for board and tx/rx pins. Also added LED just for testing, does not have practical value since board is hidden inside heater.
esp32:
board: m5stack-atom
framework:
type: arduino
uart:
id: uart_bus
tx_pin: 19
rx_pin: 22
... the rest
Full yaml
esphome:
name: navien-water-heater
friendly_name: Navien Water Heater
esp32:
board: m5stack-atom
framework:
type: arduino
# Enable Home Assistant API
api:
encryption:
key: "<redacted>"
ota:
password: "<redacted>"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Navien-Water-Heater"
password: "<redacted>"
captive_portal:
binary_sensor:
- platform: status
name: Status
internal: True
# Enable logging
logger:
level: DEBUG
logs:
uart.component: DEBUG
sensor: NONE
baud_rate: 0 #disable logging over uart
globals:
- id: init_set_temp
type: int
restore_value: yes
initial_value: '120'
light:
- platform: fastled_clockless
chipset: SK6812
pin: 27
num_leds: 1
rgb_order: GRB
name: "FastLED Light"
#################################
#### UART SETUP/DECODE BYTES ####
#################################
uart:
id: uart_bus
tx_pin: 19
rx_pin: 22
baud_rate: 19200
data_bits: 8
stop_bits: 1
parity: NONE
debug:
direction: BOTH
dummy_receiver: True
after:
delimiter: "\n"
sequence:
- lambda: |-
//
// SPECIAL THANKS TO @suva on the HomeAssistant forum for Decoding these.
// https://community.home-assistant.io/t/navien-hot-water-heater-navilink/330044/92
//
//UARTDebug::log_string(direction, bytes);
if (bytes[0] == 247 && bytes[1] == 5 && bytes[2] == 80 && bytes[3] == 80 && bytes[4] == 144 && bytes[5] == 34) {
// Water information
id(uart_water_byte0).publish_state(bytes[0]); //Common To all Packets
id(uart_water_byte1).publish_state(bytes[1]); //Common To all Packets
id(uart_water_byte2).publish_state(bytes[2]); //Packet id Byte 0
id(uart_water_byte3).publish_state(bytes[3]); //Packet id Byte 1
id(uart_water_byte4).publish_state(bytes[4]); //Packet id Byte 2
id(uart_water_byte5).publish_state(bytes[5]); //Data Length
id(uart_water_byte6).publish_state(bytes[6]);
id(uart_water_byte7).publish_state(bytes[7]);
id(uart_water_byte8).publish_state(bytes[8]);
id(uart_water_byte9).publish_state(bytes[9]); // System Power: high nibble: Unknown (values 0 and 0x20 observed); low nibble = 0=off 0x5=on
id(uart_water_byte10).publish_state(bytes[10]);
id(set_temp_read).publish_state((bytes[11]/2)); //Set temp - measured in 0.5 degrees C.
id(outlet_temp).publish_state((bytes[12]/2)); //Outlet temp - measured in 0.5 degrees C.
id(inlet_temp).publish_state((bytes[13]/2)); //Inlet temp - measured in 0.5 degrees C.
id(uart_water_byte14).publish_state(bytes[14]);
id(uart_water_byte15).publish_state(bytes[15]);
id(uart_water_byte16).publish_state(bytes[16]);
id(uart_water_byte17).publish_state(bytes[17]);
id(water_flow_lpm).publish_state(bytes[18] / 10); //Flow rate - measured in 0.1 liters per minute (divide by 10 to get LPM)
id(uart_water_byte19).publish_state(bytes[19]);
id(uart_water_byte20).publish_state(bytes[20]);
id(uart_water_byte21).publish_state(bytes[21]);
id(uart_water_byte22).publish_state(bytes[22]);
id(uart_water_byte23).publish_state(bytes[23]);
id(uart_water_byte24).publish_state(bytes[24]); //System status. Probably a bitwise field. Partially decoded: display units: 0x08 position: 1=metric 0=imperial. 0x02 position: 1=weekly 0=hotbutton
id(uart_water_byte25).publish_state(bytes[25]);
id(uart_water_byte26).publish_state(bytes[26]);
id(uart_water_byte27).publish_state(bytes[27]);
id(uart_water_byte28).publish_state(bytes[28]);
id(uart_water_byte29).publish_state(bytes[29]);
id(uart_water_byte30).publish_state(bytes[30]);
id(uart_water_byte31).publish_state(bytes[31]);
id(uart_water_byte32).publish_state(bytes[32]);
id(uart_water_byte33).publish_state(bytes[33]);
id(uart_water_byte34).publish_state(bytes[34]);
id(uart_water_byte35).publish_state(bytes[35]);
id(uart_water_byte36).publish_state(bytes[36]);
id(uart_water_byte37).publish_state(bytes[37]);
id(uart_water_byte38).publish_state(bytes[38]);
id(uart_water_byte39).publish_state(bytes[39]);
id(uart_water_byte40).publish_state(bytes[40]);
}
else if (bytes[0] == 247 && bytes[1] == 5 && bytes[2] == 80 && bytes[3] == 15 && bytes[4] == 144 && bytes[5] == 42) {
// Gas information
id(uart_gas_byte0).publish_state(bytes[0]); //Common to All Packets
id(uart_gas_byte1).publish_state(bytes[1]); //Common to All Packets
id(uart_gas_byte2).publish_state(bytes[2]); //Packet id Byte 0
id(uart_gas_byte3).publish_state(bytes[3]); //Packet id Byte 1
id(uart_gas_byte4).publish_state(bytes[4]); //Packet id Byte 2
id(uart_gas_byte5).publish_state(bytes[5]); //Data Length
id(uart_gas_byte6).publish_state(bytes[6]);
id(uart_gas_byte7).publish_state(bytes[7]);
id(uart_gas_byte8).publish_state(bytes[8]);
id(uart_gas_byte9).publish_state(bytes[9]);
id(uart_gas_byte10).publish_state(bytes[10]);
id(uart_gas_byte11).publish_state(bytes[11]);
id(uart_gas_byte12).publish_state(bytes[12]);
id(uart_gas_byte13).publish_state(bytes[13]);
id(uart_gas_byte14).publish_state(bytes[14]);
id(uart_gas_byte15).publish_state(bytes[15]);
id(uart_gas_byte16).publish_state(bytes[16]);
id(uart_gas_byte17).publish_state(bytes[17]);
id(uart_gas_byte18).publish_state(bytes[18]);
id(uart_gas_byte19).publish_state(bytes[19]);
id(uart_gas_byte20).publish_state(bytes[20]);
id(uart_gas_byte21).publish_state(bytes[21]);
id(low_byte_kcal).publish_state(bytes[22]); //Low byte current gas usage in kcal
id(high_byte_kcal).publish_state(bytes[23]); //High byte current gas usage in kcal
id(total_gas_use_m3).publish_state(bytes[24] / 10); //Total gas usage in 0.1m^3 (divide by 10 to get m^3)
id(uart_gas_byte25).publish_state(bytes[25]);
id(uart_gas_byte26).publish_state(bytes[26]);
id(uart_gas_byte27).publish_state(bytes[27]);
id(uart_gas_byte28).publish_state(bytes[28]);
id(uart_gas_byte29).publish_state(bytes[29]);
id(uart_gas_byte30).publish_state(bytes[30]);
id(uart_gas_byte31).publish_state(bytes[31]);
id(uart_gas_byte32).publish_state(bytes[32]);
id(uart_gas_byte33).publish_state(bytes[33]);
id(uart_gas_byte34).publish_state(bytes[34]);
id(uart_gas_byte35).publish_state(bytes[35]);
id(uart_gas_byte36).publish_state(bytes[36]);
id(uart_gas_byte37).publish_state(bytes[37]);
id(uart_gas_byte38).publish_state(bytes[38]);
id(uart_gas_byte39).publish_state(bytes[39]);
id(uart_gas_byte40).publish_state(bytes[40]);
} else {
// Handle other cases
}
###############################
#### ENABLE/DISABLE HEATER ####
###############################
switch:
- platform: template
name: "HW Heater On/Off"
id: navien_switch
restore_mode: ALWAYS_ON
icon: mdi:water-boiler
lambda: |-
if ((id(uart_water_byte9).state) == 5) {
return true;
id(navien_switch).publish_state(true);
} else {
return false;
id(navien_switch).publish_state(false);
}
turn_on_action:
- uart.write: !lambda
return {0xf7, 0x05, 0x0f, 0x50, 0x10, 0x0c, 0x4f, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce};
id(navien_switch).publish_state(true);
turn_off_action:
- uart.write: !lambda
return {0xf7, 0x05, 0x0f, 0x50, 0x10, 0x0c, 0x4f, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa};
id(navien_switch).publish_state(false);
- platform: template
name: "Fake Thermostat Switch"
id: fake_switch
restore_mode: ALWAYS_ON
optimistic: True
internal: True
####################################################################
#### SETPOINT ENTRY TEMPLATE - STILL WORKING ON THIS 4/29/2024 ####
####################################################################
climate:
- platform: thermostat
name: "Climate Controller"
visual:
min_temperature: 120 °F
max_temperature: 140 °F
temperature_step: 1.0 °F
sensor: outlet_temp
min_heating_off_time: 300s
min_heating_run_time: 300s
min_idle_time: 30s
heat_action:
- switch.turn_on: fake_switch
idle_action:
- switch.turn_off: fake_switch
################################
#### WATER TEMPLATE SENSORS ####
################################
sensor:
- platform: template
name: "WByte_0"
id: uart_water_byte0
internal: True
- platform: template
name: "WByte_01"
id: uart_water_byte1
internal: True
- platform: template
name: "WByte_02"
id: uart_water_byte2
internal: True
- platform: template
name: "WByte_03"
id: uart_water_byte3
internal: True
- platform: template
name: "WByte_04"
id: uart_water_byte4
internal: True
- platform: template
name: "WByte_05"
id: uart_water_byte5
internal: True
- platform: template
name: "WByte_06"
id: uart_water_byte6
internal: True
- platform: template
name: "WByte_07"
id: uart_water_byte7
internal: True
- platform: template
name: "WByte_08"
id: uart_water_byte8
internal: True
- platform: template
name: "WByte_09"
id: uart_water_byte9
internal: true
- platform: template
name: "WByte_10"
id: uart_water_byte10
internal: True
- platform: template
name: "Temp Set - Read"
id: set_temp_read
icon: mdi:thermometer-water
unit_of_measurement: °C
accuracy_decimals: 1
device_class: "temperature"
state_class: "measurement"
- platform: template
name: "Temp Outlet"
id: outlet_temp
icon: mdi:thermometer-water
unit_of_measurement: °C
accuracy_decimals: 1
device_class: "temperature"
state_class: "measurement"
- platform: template
name: "Temp Inlet"
id: inlet_temp
icon: mdi:thermometer-water
unit_of_measurement: °C
accuracy_decimals: 1
device_class: "temperature"
state_class: "measurement"
- platform: template
name: "WByte_14"
id: uart_water_byte14
internal: True
- platform: template
name: "WByte_15"
id: uart_water_byte15
internal: True
- platform: template
name: "WByte_16"
id: uart_water_byte16
internal: True
- platform: template
name: "WByte_17"
id: uart_water_byte17
internal: True
- platform: template
name: "Water Flow LPM"
id: water_flow_lpm #multiply by 0.2642 to get GPM
icon: mdi:water-percent
unit_of_measurement: l/min
- platform: template
name: "Water Flow GPM"
id: water_flow_gpm #multiply by 0.2642 to get GPM
icon: mdi:water-percent
unit_of_measurement: GPM
lambda: |-
return (id(water_flow_lpm).state * 0.2642);
- platform: template
name: "WByte_19 Unknown Flow"
id: uart_water_byte19
# internal: True
- platform: template
name: "WByte_20"
id: uart_water_byte20
internal: True
- platform: template
name: "WByte_21"
id: uart_water_byte21
internal: True
- platform: template
name: "WByte_22"
id: uart_water_byte22
internal: True
- platform: template
name: "WByte_23"
id: uart_water_byte23
internal: True
- platform: template
name: "WByte_24 Sys Status"
id: uart_water_byte24
# internal: True
- platform: template
name: "WByte_25"
id: uart_water_byte25
internal: True
- platform: template
name: "WByte_26"
id: uart_water_byte26
internal: True
- platform: template
name: "WByte_27"
id: uart_water_byte27
internal: True
- platform: template
name: "WByte_28"
id: uart_water_byte28
internal: True
- platform: template
name: "WByte_29"
id: uart_water_byte29
internal: True
- platform: template
name: "WByte_30"
id: uart_water_byte30
internal: True
- platform: template
name: "WByte_31"
id: uart_water_byte31
internal: True
- platform: template
name: "WByte_32"
id: uart_water_byte32
internal: True
- platform: template
name: "WByte_33"
id: uart_water_byte33
internal: True
- platform: template
name: "WByte_34"
id: uart_water_byte34
internal: True
- platform: template
name: "WByte_35"
id: uart_water_byte35
internal: True
- platform: template
name: "WByte_36"
id: uart_water_byte36
internal: True
- platform: template
name: "WByte_37"
id: uart_water_byte37
internal: True
- platform: template
name: "WByte_38"
id: uart_water_byte38
internal: True
- platform: template
name: "WByte_39"
id: uart_water_byte39
internal: True
- platform: template
name: "WByte_40"
id: uart_water_byte40
internal: True
##############################
#### GAS TEMPLATE SENSORS ####
##############################
- platform: template
name: "GByte_0"
id: uart_gas_byte0
internal: True
- platform: template
name: "GByte_01"
id: uart_gas_byte1
internal: True
- platform: template
name: "GByte_02"
id: uart_gas_byte2
internal: True
- platform: template
name: "GByte_03"
id: uart_gas_byte3
internal: True
- platform: template
name: "GByte_04"
id: uart_gas_byte4
internal: True
- platform: template
name: "GByte_05"
id: uart_gas_byte5
internal: True
- platform: template
name: "GByte_06"
id: uart_gas_byte6
internal: True
- platform: template
name: "GByte_07"
id: uart_gas_byte7
internal: True
- platform: template
name: "GByte_08"
id: uart_gas_byte8
internal: True
- platform: template
name: "GByte_09"
id: uart_gas_byte9
internal: true
- platform: template
name: "GByte_10"
id: uart_gas_byte10
internal: True
- platform: template
name: "GByte_11"
id: uart_gas_byte11
internal: True
- platform: template
name: "GByte_12"
id: uart_gas_byte12
internal: True
- platform: template
name: "GByte_13"
id: uart_gas_byte13
internal: True
- platform: template
name: "GByte_14"
id: uart_gas_byte14
internal: True
- platform: template
name: "GByte_15"
id: uart_gas_byte15
internal: True
- platform: template
name: "GByte_16"
id: uart_gas_byte16
internal: True
- platform: template
name: "GByte_17"
id: uart_gas_byte17
internal: True
- platform: template
name: "GByte_18"
id: uart_gas_byte18
internal: True
- platform: template
name: "GByte_19"
id: uart_gas_byte19
internal: True
- platform: template
name: "GByte_20"
id: uart_gas_byte20
internal: True
- platform: template
name: "GByte_21"
id: uart_gas_byte21
internal: True
- platform: template
name: "GByte_22"
id: uart_gas_byte22
internal: True
- platform: template
name: "GByte_23"
id: uart_gas_byte23
internal: True
- platform: template
name: "GByte_24"
id: uart_gas_byte24
internal: True
- platform: template
name: "GByte_25"
id: uart_gas_byte25
internal: True
- platform: template
name: "GByte_26"
id: uart_gas_byte26
internal: True
- platform: template
name: "GByte_27"
id: uart_gas_byte27
internal: True
- platform: template
name: "GByte_28"
id: uart_gas_byte28
internal: True
- platform: template
name: "GByte_29"
id: uart_gas_byte29
internal: True
- platform: template
name: "GByte_30"
id: uart_gas_byte30
internal: True
- platform: template
name: "GByte_31"
id: uart_gas_byte31
internal: True
- platform: template
name: "GByte_32"
id: uart_gas_byte32
internal: True
- platform: template
name: "GByte_33"
id: uart_gas_byte33
internal: True
- platform: template
name: "GByte_34"
id: uart_gas_byte34
internal: True
- platform: template
name: "GByte_35"
id: uart_gas_byte35
internal: True
- platform: template
name: "GByte_36"
id: uart_gas_byte36
internal: True
- platform: template
name: "GByte_37"
id: uart_gas_byte37
internal: True
- platform: template
name: "GByte_38"
id: uart_gas_byte38
internal: True
- platform: template
name: "GByte_39"
id: uart_gas_byte39
internal: True
- platform: template
name: "GByte_40"
id: uart_gas_byte40
internal: True
- platform: template
name: "Total Gas Use Cubic Meters"
id: total_gas_use_m3 # multiply by 0.3508 to get therms
icon: mdi:gas-cylinder
unit_of_measurement: m³
accuracy_decimals: 1
- platform: template
name: "Total Gas Use Therms"
id: total_gas_use_therms # multiply by 0.3508 to get therms
icon: mdi:gas-cylinder
unit_of_measurement: therms
accuracy_decimals: 1
lambda: |-
return (id(total_gas_use_m3).state * 0.358);
- platform: template
name: "kCal Low Byte"
id: low_byte_kcal
icon: mdi:gas-burner
unit_of_measurement: kCal
- platform: template
name: "kCal High Byte"
id: high_byte_kcal
icon: mdi:gas-burner
unit_of_measurement: kCal
- platform: template
name: "Instant BTUs"
id: instant_btus
icon: mdi:gas-burner
unit_of_measurement: "kbtu/hr"
accuracy_decimals: 3
state_class: "measurement"
lambda: |-
return max((id(outlet_temp).state - id(inlet_temp).state) * id(water_flow_gpm).state * 8.334 * 60 / 0.92 / 1000, 0.0);
# calculated as shown here https://www.plctalk.net/threads/low-byte-high-byte.78315/
- platform: template
name: "Total kCal"
id: total_kcal
icon: mdi:gas-burner
unit_of_measurement: kCal
accuracy_decimals: 2
state_class: "measurement"
lambda: |-
return (id(high_byte_kcal).state*256) + (id(low_byte_kcal).state);
1 Like
@kkopachev - Thanks! I was going down the same path but since mine is not installed yet, I was not seeing anything and wasn’t sure whether the RS485 base needed to be supported with some custom component given it also has i2c which we are not using. I wonder what it is for… will research.
I want to place the ESP outside the chassis, probably using a magnet to attach on a side, so I need a longer cable. I wish I could find the XHB connectors to crimp on amazon but no luck yet. Also, not sure I want a huge number for just one connector given I don’t typically use them.
Has some of this communication happened without an NaviLink in place?
brystmar
(Thomas)
May 22, 2024, 11:21pm
54
My 10-pack of connectors with 300mm cables is currently crossing the pacific. Happy to send a couple your way once they land.