I use three DS18B20 sensors, all in the TO92 package (like a transistor) rather than the waterproof type in a chrome cylinder. These are wired together on the same 1-Wire bus (actually three wires required: I used stripped-out Cat5e cable with the data and ground as a twisted pair).
That bus then connects to my central heating controller which is a Wemos D1 Mini ESP8266 device, taking over the job from the Danfoss “dumb” proprietary unit I used to have. That unit also switches the hot water and central heating on and off, but if you just want the measurement you don’t need any of the relay hardware.
Code is with ESPHome: start here:
That provides HA with three temperature readings. I then combine these with a template sensor to provide the “raw” value referred to above:
- name: "Hot water raw tank charge"
unique_id: f4a53dbd-12da-40d9-9f45-a71c143d2e67
unit_of_measurement: '%'
icon: mdi:thermometer
state: >-
{{ ((([0, [50, (states('sensor.tank_top')|float(0.0))]|min - 35]|max) * 1.0) +
(([0, [55, (states('sensor.coil_inlet')|float(0.0))]|min - 35]|max) * 3.75) +
(([0, [40, (states('sensor.coil_return')|float(0.0))]|min - 35]|max) * 2))|round(2) }}
Those weightings are trial-and-error approximations for my tank, with 35°C being “cold” and the other numbers being “fully hot” for that segment. For example, if the immersion has been running such that the top sensor is over 50°C but the other two are below 35°C, it reports 15% ((50-35)*1.0); and if they’re all above their “hot” limit, it adds up to 100%.
The automation above then smooths them and stores the value in the input_number
; and I have a second template sensor that reads this and provides a sensor value with icon:
- name: "Hot water tank charge"
unique_id: c2d75699-11bf-4aa2-a337-b26f282be395
unit_of_measurement: '%'
icon: >-
{% if states('binary_sensor.hw_running') == 'on' or
states('sensor.immersion_switch_power')|int(0) > 100 %}
mdi:battery-charging-outline
{% elif states('sensor.hot_water_tank_charge')|int(0) < 10 %}
mdi:battery-alert-variant-outline
{% elif states('sensor.hot_water_tank_charge')|int(0) < 100 %}
mdi:battery-{{ 10-(states('sensor.hot_water_tank_charge')[0]|int(0)) }}0
{% else %}
mdi:battery-outline
{% endif %}
state: "{{ states('input_number.hw_tank_smooth_value')|round(0) }}"
There’s probably an easier more compact way in the new era of trigger-based template sensors, but this works for me.
My hot water scheduling is described in this post:
and then optimised further in this one: