Water Softener Salt Level Checker (Using – NodeMCU/HomeAssistant)

I frequently forget to put salt in my water softener and as an IoT solution I sometime back came up with a small circuit that would let me check the Salt level remotely on my laptop or mobile, and push Email/SMS Alerts when the salt level gets down below a certain level.

For the setup I’m uisng a NodeMCU module (Any ESP8266 board would work), an Ultrasonic distance sensor, and my Home Assistant installation. The NodeMCU will be programmed using ESPHome.

The Ultrasonic Sensor Used here is HC-SR04

NodeMCU board

Here I’m measuring the distance from top of the bin to the salt surface level and getting the height of salt by subtracting that measurement from the total bin height.

Salt Height = Total Bin Height – Distance from Top to Salt Level Surface

This is the wiring diagram for the ModeMCU and HC-SR04 (Ultrasonic) module.

We connect the Trigger pin of the Ultrasonic Module to the GPIO4 Pin (D2) of the NodeMCU and the Echo pin to the GPIO5 pin (D1) of NodeMCU. I also included a reset button which I can use to reset the IoT device manually if needed. It momentarily connects the GND with RST Pin causing the module to reboot. Furthermore the GPIO16 (D0) Pin also needs to be connected to RST Pin, this will send the Wake signal (Low signal/0) to the RST Pin at the end of deep sleep. If this connection is not done the module will not automatically wake up after deep sleep.

I read somewhere that some HC-SR04 modules need an input voltage on 5V, therefore please check the datasheet of the module you buy to make sure if it needs 3.3V or 5V. If you need 5V you can get a 5V output from the Vin Pin of NodeMCU which will have the input voltage of the USB cable (5v).

When it comes to the ESPHome yaml file;

  • it wakes up the device every 30 minutes;
  • measures the distance to the salt surface
  • calculates the salt height
  • publishes the height to MQTT
  • goes back to sleep 30 minutes

Here the Ultrasonic distance sensor reports the distance in meters when we use ESPHome. To convert it to inches we must multiply by 39.3701 (because; 1m=39.3701 inches)

In my case the salt bin was 33 inches in height, and the salt height would be = (33-(x*39.3701)) inches

(x being the value returned from the Ultrasonic module)

Here’s the yaml file for ESPHome.

(Note: Explicitly defined “birth_msg” and “will_msg” here since this device will be offline during deep sleep, and I wanted to disable the availability on HA for this node)

  name: salt_checker
  platform: ESP8266
  board: nodemcuv2

  ssid: <Your_Wifi_SSID>
  password: <Your_Wifi_Password>
    static_ip: <Static_IP_for_this_device>
    gateway: <Gateway_IP>
    subnet: <Subnet_Mask>

  broker: <MQTT_Broker_IP>
  username: <MQTT_Username>
  password: <MQTT_Password>
    topic: salt_checker/birth_msg
    payload: disable
    topic: salt_checker/will_msg
    payload: disable
  client_id: salt_checker


# Enable logging

 password: "<some_password_here>"

 - platform: ultrasonic
   trigger_pin: 4
   echo_pin: 5
   name: "Salt Level"
   - lambda: return ( 33 - ( x * 39.3701 ) );
   - filter_out: nan
   unit_of_measurement : "in"
   update_interval: 30s
   accuracy_decimals: 3

  id: deep_sleep_1
  sleep_duration: 30min

I drilled two holes in the salt bin lid to slide the Ultrasonic sensor eyes through it and mounted the plastic enclosure around it on the top side. After uploading the bin file generated from ESPHome, the NodeMCU was also put in place.

Here’s how it looked.

After uploading the bin file generated from the ESPHome yaml, and powering it on, we need to add this as a sensor in Home Assistant. If you search for the “sensor.salt_level” entity in HA it should be possible to add it to a card in Lovelace UI.

There are some additional steps I did to get the percentage of salt above the brine solution level. I’m using MQTT and Nodered to do this.

Here I’m doing a calculation based on how much salt I have above the brine level as a percentage. I found out the height of the brine solution by letting the water softener to run without salt for couple of days and measured the height for the brine solution.

Usable Salt Percentage % = ( (Salt Height – Brine Hight)/(Total Bin Height – Brine Height) )* 100

In my case the Total Bin Height is 33 inches, and the brine height is around 10 inches.


Usable Salt Percentage % = ( (Salt Height – 10)/(33 – 10) )* 100

Usable Salt Percentage % = ( (Salt Height – 10)/(23) )* 100

The salt level (in inches) can be fetched by an MQTT client uisng the MQTT topic which it reports to.

We can find this by going to; HA –> Configuration –> Integrations –> MQTT –> Devices –> <Select your ESPHome Device> –> In the “Device Info” Card go to “MQTT INFO”.

Here under “Entities” you can see the “<ESPHome_Device_Name>/sensor/salt_level/state” topic which the ESPHome device uses to report the salt height (salt level) in inches to Home Assistant. I’m using this MQTT message as an input to calculate the percentage of salt above the brine level and push the output of that back to Home Assistant as another sensor.

Here’s a sample Nodered flow which can be used to achieve that.

Now we need to define the MQTT topic “<device_name>/salt_pct” as a sensor in Home Assistant. Here’s what that looks like in configuration.yaml file.

- platform: mqtt

  name: "Salt Percentage"

  state_topic: “<device_name>/salt_pct”

  unit_of_measurement: '%'

After restarting the HA instance, we can add this to Lovelace UI the same way as we did before.

search for the “sensor.salt_percentage” and add it to a card. Rename the attribute if you wish so.

Additionally, you can add an automation in HA to monitor these values and generate alerts if salt level gets below a certain level. Nodered can also be used to generate alerts (email or SMS text) by monitoring the respective MQTT topics; is you want to go that route.

As always thanks for reading and thanks for your interest!