Water Softener Salt Level with EZsalt

It’s you cable. Flashing an ESP32 is trivial. Google it and follow the instructions.

its not my damn cable. I’m using one from an xbox controller that’s good for data. Tried 3 others also for good measure. I imagine its a driver issue - which driver if any did you need to install, and what OS are you installing from? Which browser? As i said, i’ve flashed m5atoms and a bunch of sonoff 8266 fan controllers without problems.

This is an EZsalt 3.0 if that makes a difference.

edit: Tried about 20 more cables. Its not the cable. Can anyone with a EZSalt 3.0 (not 2.0) please confirm that this worked for them, and whether or not you had to hold down the button to put it in flash mode? Also bonus points if you installed any particular driver (i believe you shouldn’t need one if it has a USB controller but i could be wrong)

I also tried from my laptop but it doesn’t appear to have a COM port at all. Bit confused about Windows and COM ports. Tried connecting right to the HA box also but it only ever shows my skyconnect as a valid USB device.

Michael, are you saying its impossible to flash with the 3.0 over USB, regardless of cable? So we’d have to crack open the case to do it?

Post a picture of the ESP32

Trying to get the Ezsalt 3 working here also. Jeremy, the way you get this into boot mode is connecting the gpio0 to gnd and then plug in the usb to power. after a second remove the gio0 to gnd jumper and it should be in boot mode.

I can not get the chip to see the sensor though. not sure if its different from the OP’s or not. I have a feeling he may have an older version.

What tof sensor are you using in the ezsalt 3? Is it a VL53L5x? also what pins are they connected to? Trying to get this working.

I gave up trying to re-flash the EZSalt and simply changed it’s MQTT reference to point to the MQTT instance in HA. It will show up as a Tasmota integration when HA discovers it. Then install the “Template” integration and I coded the formula below to report the tank salt level as a percentage. (NOTE: the 110 is an offset from 100% from the top of the salt to the top of the sensor. The 39 is the tank depth). I’m on my way out the door so if you have any questions, I’ll be glad to get back to you later.

template:
  - sensor:
      - name: "EzSalt Tank Percentage"
        unique_id: ezsalt_tank_percentage
        unit_of_measurement: "%"
        state: "{% set raw_value = states('sensor.ezsalt_vl53l0x_distance') %}
          {% set inches = raw_value | float(0) %}
          {% if inches > 0 %}
          {% set percentage = 110 - ((inches / 10) / 39) * 100 %}
          {{ percentage | round(0) }}
          {% else %}
          0
          {% endif %}"

Host=IP of your HA install
User/Password=a user set up in your HA install

I am not sure how to get the original firmware back onto it. So at this point i am all in. I reached out to them via their website to see if we can get some info on the sensor and gpio pins used.

I’m sorry about that. If they don’t/can’t give you a way to do it yourself, perhaps they will re-flash it for you. One of the main reasons I stuck with the OEM firmware is that I read they will be opening up their API and making it public this year. Someone should be able to build a proper HA integration when that happens.

For those of you trying to get this working with a V3 sensor, it is a VL53L0x sensor with SDA on GPIO5 and SCL on GPIO4 and an address of 0x29.

I had to pop the cap off the sensor to trace out the board to figure it out, then trial and error the SDA and SCL pins using an I2C scanner sketch to figure out which was which, but I figured it out and confirmed it works.

Additionally, the xshut pin on the VL53L0x is wired to GPIO12, and if I traced it out properly, AVDDVCSEL is wired through a transistor connected to GPIO2. Driving both of those low I believe would essentially put the TOF sensor into deep sleep mode.

The LED is a two color hanging off of GPIO13 and GPIO14, and the switch is hanging off of GPIO15.

Unfortunately, they did not include a UART to USB chip for the USB port, so the ONLY way to program it is with an external UART to USB. They did a nice job of breaking out all the necessary pins, including 3.3v, GPIO0 and RST to a pin header, so it’s not a huge deal once you get the case open.

To restore back to “factory” You should be able to download tasmota.bin.gz from here: Tasmota ESP8266 Binaries

And then add the template using configure other: Templates - Tasmota

Template: {“NAME”:“EZsalt Sensor v3”,“GPIO”:[0,0,0,0,608,640,0,0,256,257,544,96,0,0],“FLAG”:0,“BASE”:18}

If you want the MQTT info for EZSalt I can send to you privately.

Since this is based off of Tasmota you can do an OTA or local upgrade.

I am going to try this this weekend: Migrating from Tasmota — ESPHome

Based on their template I don’t see anything on GPIO2 but it could be for later use if you traced it there, thanks for all the sleuthing!

This is my project with VL53l0x and ESP32-S3 + AM2302 + Ble Tracker, works like a charm.

sensor:
  - platform: vl53l0x
    id: salt_level_distance_2
    name: "medicion-2"
    address: 0x29
    update_interval: 5s
    long_range: false
    internal: True
    unit_of_measurement: "m"
    accuracy_decimals: 3
 
  - platform: template
    unit_of_measurement: cm
    icon: mdi:arrow-expand-down
    name: "Distancia"
    id: distance
    update_interval: 5s
    lambda: |- 
      return id(salt_level_distance_2).state * 100;
   
  - platform: wifi_signal
    name: "WiFi"
    update_interval: 60s

  - platform: dht
    model: AM2302
    pin: GPIO12
    temperature:
      name: "Temp Exterior"
    humidity:
      name: "Humedad Exterior"
    update_interval: 15s
  
  - platform: template
    name: "Nivel de Sal"
    icon: mdi:arrow-expand-vertical
    #empty_cm, CM before bottom of the tank.
    #full_cm, CM from the sensor to salt.
    lambda: |-
      float empty_cm = 62.0;
      float full_cm = 15.0;
      float current_cm = id(distance).state;
      return ((empty_cm - current_cm) / (empty_cm - full_cm)) * 100.0;
    unit_of_measurement: "%"
    accuracy_decimals: 1

switch:
- platform: restart
  name: "Reboot"


esp32_ble_tracker:
  scan_parameters:
    window: 400ms
    interval: 600ms

bluetooth_proxy:
  active: True

Converting EZ Salt 3.0 from Tasmota to ESPHome

If you have an EZ Salt 3.0 device currently running Tasmota and want to convert it to ESPHome for better Home Assistant integration, this guide will walk you through the complete process.

What is the EZ Salt 3.0?

The EZ Salt 3.0 is an ESP8266-based sensor device designed for monitoring salt levels in water softener systems. It features:

  • VL53L0x Time-of-Flight sensor for distance measurement
  • Two-color LED for status indication
  • Physical button for manual control
  • WiFi connectivity for remote monitoring

Hardware Details

Based on reverse engineering the device, here’s the complete pinout:

  • VL53L0x Sensor: SDA on GPIO5, SCL on GPIO4, Address 0x29
  • Power Management: XSHUT on GPIO12, AVDDVCSEL control via transistor on GPIO2
  • Status LED: Two colors on GPIO13 and GPIO14
  • Physical Switch: GPIO15 with internal pull-up
  • I2C Bus: 400kHz frequency

Prerequisites

Before starting, you’ll need:

  1. ESPHome installed (via Home Assistant Add-on or standalone)
  2. WiFi access to connect to the device
  3. USB cable or OTA capability for flashing
  4. The device currently running Tasmota firmware

Step-by-Step Conversion Process

Step 1: Connect to the Tasmota Device

Since your EZ Salt 3.0 is currently running Tasmota:

  1. Find the device’s IP address in your router’s admin panel or use network scanning
  2. Open a web browser and navigate to the device’s IP address
  3. Access the Tasmota web interface

Step 2: Prepare for ESPHome Flash

  1. Backup your current configuration (optional but recommended)
  2. Note your WiFi credentials - you’ll need them for the ESPHome config
  3. Prepare the ESPHome firmware using the configuration below

Step 3: Flash ESPHome Firmware

You have two options for flashing:

Option A: OTA Flash (Recommended)

  1. In the Tasmota web interface, go to Firmware Upgrade
  2. Upload the compiled ESPHome .bin file
  3. Wait for the device to reboot

Option B: USB Flash (you will need to modify the board for this)

  1. Connect the device via USB
  2. Use ESPHome’s flash command: esphome run ezsalt-v3.yaml

Step 4: Configure WiFi

After flashing, the device will create a fallback hotspot:

  1. Connect to the WiFi network: EZSalt_v3_Fallback_AP
  2. Use password: configureme
  3. Navigate to: http://192.168.4.1
  4. Enter your WiFi credentials

ESPHome Configuration

Save this configuration as ezsalt-v3.yaml and customize it for your setup:

esphome:
  name: ezsalt-v3
  friendly_name: "EZ Salt v3 Sensor"

esp8266:
  board: nodemcuv2

wifi:
  ssid: "YOUR_WIFI_SSID"
  password: "YOUR_WIFI_PASSWORD"
  # Optional: Enable fallback hotspot in case of WiFi connection failure
  ap:
    ssid: "EZSalt_v3_Fallback_AP"
    password: "configureme"

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:
  platform: esphome

# Add web server for direct access
web_server:
  port: 80

i2c:
  sda: GPIO5
  scl: GPIO4
  scan: true

# Power management outputs for VL53L0x sensor
output:
  # VL53L0x AVDDVCSEL control via transistor
  - platform: gpio
    id: vl53l0x_avdd_pin
    pin: GPIO2
  
  # LED outputs for the two-color LED
  - platform: esp8266_pwm
    id: led_color_1_pin_output
    pin: GPIO13
  - platform: esp8266_pwm
    id: led_color_2_pin_output
    pin: GPIO14

# Add restart button for convenience
button:
  - platform: restart
    name: "Restart"

# VL53L0x power management
switch:
  - platform: output
    name: "VL53L0x Power"
    output: vl53l0x_avdd_pin
    id: sensor_power
    restore_mode: RESTORE_DEFAULT_ON

# System info sensors
text_sensor:
  - platform: wifi_info
    ip_address:
      name: "IP Address"
      id: ip_address
      icon: mdi:ip-network
    ssid:
      name: "SSID"
      id: ssid
      icon: mdi:wifi

sensor:
  # System monitoring
  - platform: uptime
    name: "Uptime"
    
  - platform: wifi_signal
    name: "WiFi Signal"
    id: wifi_signal_strength
    update_interval: 60s
    icon: mdi:wifi-strength-1
    
  # VL53L0x distance sensor
  - platform: vl53l0x
    name: "Salt Level Distance"
    id: salt_level
    address: 0x29
    update_interval: 10s
    unit_of_measurement: "cm"
    accuracy_decimals: 1
    filters:
      - multiply: 100  # Convert from meters to centimeters

# Two-color status LED
light:
  - platform: binary
    name: "Status LED Green"
    output: led_color_1_pin_output
    id: led_color_1
  - platform: binary
    name: "Status LED Red"
    output: led_color_2_pin_output
    id: led_color_2

# Physical switch
binary_sensor:
  - platform: gpio
    pin:
      number: GPIO15
      mode: INPUT_PULLUP
      inverted: true
    name: "Device Physical Switch"
    filters:
      - delayed_on: 10ms
      - delayed_off: 10ms

Configuration Customization

Required Changes

  1. WiFi Credentials: Replace YOUR_WIFI_SSID and YOUR_WIFI_PASSWORD with your actual network details
  2. Device Name: Change ezsalt-v3 if you want a different hostname
  3. Friendly Name: Modify the friendly name to match your preference

Optional Customizations

  1. Update Intervals: Adjust sensor update frequencies based on your needs
  2. LED Colors: Rename the LED entities to match your device’s actual colors
  3. Encryption: Add an API encryption key for enhanced security
  4. OTA Password: Add a password for over-the-air updates

Adding Encryption (Recommended)

For enhanced security, add these to your configuration:

api:
  encryption:
    key: "YOUR_32_CHAR_ENCRYPTION_KEY_HERE"

ota:
  platform: esphome
  password: "your_ota_password"

Calibration and Usage

Distance Sensor Calibration

The sensor reports distance in centimeters. To convert this to actual salt level:

  1. Measure your salt tank height when empty
  2. Note the distance reading when the tank is full vs. empty
  3. Add a template sensor to calculate percentage or actual level

Example template sensor for salt level percentage:

sensor:
  - platform: template
    name: "Salt Level Percentage"
    unit_of_measurement: "%"
    accuracy_decimals: 0
    lambda: |-
      float empty_distance = 80.0;  // Distance when tank is empty (cm)
      float full_distance = 20.0;   // Distance when tank is full (cm)
      float current_distance = id(salt_level).state;
      
      if (current_distance > 0) {
        float percentage = ((empty_distance - current_distance) / (empty_distance - full_distance)) * 100;
        return max(0.0f, min(100.0f, percentage));
      }
      return 0.0;

Home Assistant Integration

Once configured, the device will automatically appear in Home Assistant if you have the ESPHome integration installed. You’ll get:

  • Salt level distance sensor
  • System monitoring (uptime, WiFi signal, IP address)
  • LED controls for status indication
  • Physical switch state
  • Power management switch for the sensor
  • Restart button for remote reboots

Troubleshooting

Common Issues

  1. Sensor shows “unknown”: Check I2C connections and power management switch
  2. WiFi connection fails: Verify credentials and signal strength
  3. Compilation errors: Ensure ESPHome version compatibility
  4. Sensor readings incorrect: Verify the distance unit conversion

Debug Mode

For troubleshooting, enable debug logging:

logger:
  level: DEBUG
  logs:
    i2c: DEBUG
    vl53l0x: DEBUG

I2C Scanner

The configuration includes I2C scanning. Check logs for:

Found i2c device at address 0x29

Remember to customize the configuration for your specific setup and test all functions after flashing. The power management features allow you to control the sensor remotely, and the built-in web server provides easy access for debugging and monitoring.

Happy monitoring!

Thank you very much for this great set of instructions obiwantoby.

Just a tip for others: When I try to upload my new ezsalt-v3.bin file I get the message " Upload Failed Not enough space" from the Tasmota web interface I realized that it needed to be gzip’ed first. It worked perfectly then!

Any one selling these or are they all DIY?

Available on Amazon. https://tinyurl.com/2bec4nzh

That is correct on the 3.0 sensor. The USB port does not support data transfer. The only way to reflash an 3.0 sensors to crack open the case and wire up a serial connection manually. It’s a bit of a pain, but as we are mass producing these in huge quantities, it saved us about two dollars per unit to not have data transfer capability. Our 2.0 sensors do though and that is probably what the OP has. If you would like, I have a bunch of old 2.0 sensors and a bunch of ultrasonic sensors wired up to a NodeMCU dev board that I’d be happy to sell to you for cheap ($20). If you want to email us at [email protected] and ask for older devices that support data transfer, we’ll hook you up while supplies last. Just screenshot this message and send it.

Honestly, we just need someone to help us write it! No one on our team is expert in home assistant, but we do have open API‘s that a developer who is familiar with both platforms could play around with them build something pretty cool!

EZsalt Sensor v3 (Tasmota) – Local MQTT + Cloud App Working + Salt % Template

I recently integrated an EZsalt Sensor v3 (stock firmware, Tasmota 14.2.0.6) into Home Assistant while keeping the official EZsalt mobile app fully functional.

This required no firmware flashing — just MQTT + a Mosquitto bridge.


:bullseye: Goal

  • Keep EZsalt cloud app working
  • Bring device fully into Home Assistant
  • Use local MQTT
  • Maintain clean architecture

:brick: Architecture

Instead of letting the device talk directly to mqtt.ezsaltgo.com, I pointed it at my Home Assistant Mosquitto broker and created a bridge upstream.

EZsalt (Tasmota)
↓
Home Assistant Mosquitto
↓
Bridge → mqtt.ezsaltgo.com

This gives:

  • Local-first MQTT
  • App still functional
  • Single MQTT connection from device
  • No firmware modification

:fire: Important: VLAN Firewall Rule

My EZsalt lives on an IoT VLAN (192.168.107.x) and HA is on 192.168.1.x.

I had to allow:

  • IoT VLAN → HA server
  • TCP port 1883

Once that rule was added, the device connected immediately.


:bridge_at_night: Mosquitto Bridge Config (HA Add-on)

Create:

/share/mosquitto/ezsalt_bridge.conf

EZsalt_%06X → Is your client

Contents:

connection ezsalt_cloud
address mqtt.ezsaltgo.com:1883

remote_username ezsaltsensor
remote_password <your_password_here>

topic tele/EZsalt_%06X/# both 0
topic stat/EZsalt_%06X/# both 0
topic cmnd/EZsalt_%06X/# both 0

Enable in Mosquitto add-on config:

customize:
active: true

Restart Mosquitto.

After that:

  • Tasmota auto-discovered in HA
  • EZsalt app continued working

:straight_ruler: Converting Distance → Salt %

The EZsalt app calibration shows:

  • Laser Distance: 8 in
  • Tank Depth: 38 in
  • Offset: 0

Formula used by the app:

Percent = (TankDepth − LaserDistance − Offset) / TankDepth


:warning: Important Gotcha (Scaling Issue)

Home Assistant reported:

sensor.ezsalt_vl53l0x_distance = 80

But the EZsalt app showed:

Laser Distance = 8 in

So HA was reporting 10× the value.

To match the app, I had to divide by 10 in the template.


:white_check_mark: Final Template Sensor

Create a Template Sensor with:

{% set laser_in = (states('sensor.ezsalt_vl53l0x_distance')|float(0)) / 10 %}
{% set tank_depth_in = 38 %}
{% set offset_in = 0 %}
{% set current_depth = tank_depth_in - laser_in - offset_in %}
{% set pct = 100 * (current_depth / tank_depth_in) %}
{{ [0, [pct, 100] | min] | max | round(0) }}

Unit: %

This now matches the EZsalt app exactly (79% in my case).


:white_check_mark: Final Result

  • Salt % in Home Assistant
  • EZsalt cloud app still working
  • Fully local MQTT
  • No firmware flashing
  • Clean VLAN-friendly setup