Navien, ESP32 Navilink interface

@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.

@aruffell Good catch! Apparently too much copying and pasting lately! :slight_smile: 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.

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

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

@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

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?

My 10-pack of connectors with 300mm cables is currently crossing the pacific. Happy to send a couple your way once they land.

Hey @vodkatea Yes this is running stand alone. I donā€™t even own a Navilink device.

This is an amazing thing to watch developing. I have a Navien boiler that I would like to monitor remotely at my off-grid cabin, and it looks like all the work to get what I want has already been done on this thread (mostly by tsquared & suva ā€“ great work!). I already developed a whole client-server-esp8266 system for remote control and monitoring before I even found out about HomeAssistant. (Iā€™ve put it all on Github under my judasgutenberg account. GitHub - judasgutenberg/Esp8266_RemoteControl: A server-client system for remotely controlling distant services using Esp8266s and a PHP web server. ) Next weekend when I am at the cabin I will see if I can put this info to use and perhaps give this thread an update of what I find.

@brystmar - Thank you for the offer! I just realized that my favorite connectors for my own projects are JST-XH and that they fit nicely into the XHB socket even though they donā€™t have a retainer clip. I did order a set of 20 5P XHB connectors, also on their way across the Pacific, but I can make a cable today using the XH connectors and just secure it to the cable next to it for the time being. This way, I can try to contribute more meaningfully to the project right away :slight_smile:

In reviewing the code, it is all in ā€œstandardā€ (sorry, using this term always makes me laughā€¦ given the only countries that donā€™t use Metric are United States, Liberia, and Myanmar). While I live in the USA, I am European and prefer the Metric system so Iā€™ll be working to adapt the code to show both units. I need both so I can compare apples to apples when looking at bills for example.

Edit: Cable finished (with temporary XH connector). I used silicone wires to keep it nice and bendy and also in case of heat exposure. For the nit-picky :wink: I used yellow instead of red as in my projects red is always 5V and yellow is 12V as in this case.

5 Likes

@tsquared et al., you rock! I plugged in the ESP32 and it seems to work flawlessly! I thought the code converted everything to ā€œstandardā€ but it is only partial so I will try to add new entities to show metric as well.

@tsquared - I believe I read one of your posts stating you are looking into implementing the ā€œhot buttonā€ functionality, is that correct? I mean the ability to press the button via HA. While I do not have the PCB, I do have the pump in the heater and am planning on adding the loop so I can enable it. Luckily I have easy access to the plumbing where needed. Would I need the PCB if implemented in HA? I would assume notā€¦ butā€¦ :man_shrugging:

Edit: Actually, I was totally offā€¦ the majority is already in metric :smiley:

Edit2: While the XH connector does not have retention clip, once I installed the wires in the shell and plugged it in, I found that it makes a very solid connection and it is hard to pull it out so likely totally fine as is.

@aruffell Glad this worked - I love the M5 stack solution! Itā€™s so neat & tidy - great find @kkopachev! Mine is on the way!

@aruffell Itā€™s funny you ask about the ā€œstandardā€ vs metric. I originally wrote it all in ā€œstandardā€ and then realized that when you import them into HA, the frontend of HA does the conversion for you depending on which you have your settings configured for! So, I went back and changed it all so that it was provided in metric and selectable by the users front end settings. Glad this worked also! :slight_smile:
Your question about the hot button - Well that was my original intent, Yes. However, I have a NPE-210S which apparently does not support this feature (doh!), and thus does not allow for this board so I am not 100% sure if itā€™s necessary or not.

Bummer that @tsquaredā€™s Navien doesnā€™t support HotButton. That said, itā€™s entirely possible that the unit actually does support it and the trigger simply isnā€™t exposed to the user in their first-party app. Worth a shot, right?

Fortunately my NPE-240A2 officially supports HotButton, and Iā€™d love the ability to trigger that via HA. @aruffell: Mind leaving some breadcrumbs as you implement this? Iā€™d love to follow along and learn more about this stuff.

Just received my M5 stack order. Gonna attempting flashing everything now so Iā€™m ready to rock once my connectors finish their swim across the ocean :sunglasses:.

One more thing: that cable braid & heatshrink is beautiful, @aruffell. Iā€™ve seen that done before but never attempted it myself. What products & tools would I need to do something similar? Iā€™d love to add a level of polish to my projects.

I may have found a bug in your config. Itā€™s probably moot since you discovered HA localizes imperial units to/from metric based on your profile settings. Here it is anyway.

In a comment, you mention to multiply the cubic meter value by 0.3508 to convert to therms. Your lambda function appears to multiply by 0.358 instead:

- 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);

Typo aside, is this the correct conversion rate for natural gas in the US?

Insert obligatory agreement that imperial units are silly and we really should stop using them.

1 Like