@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! 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.
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
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);
@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.
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
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 I used yellow instead of red as in my projects red is always 5V and yellow is 12V as in this case.
@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ā¦
Edit: Actually, I was totally offā¦ the majority is already in metric
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!
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 .
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?
- omnicalculator.com uses 0.364406780
- convert-me.com lists the rate as 0.35077607101
- If Iām reading this table correctly, Energy Star uses 0.36303 in the US and 0.36425 in Canada.
Insert obligatory agreement that imperial units are silly and we really should stop using them.