Water softener (CLACK WS1) consumed m3/liter monitoring

I have a water softener CLACK WS1 with a salt container. It was set that it regenerates at night when X m3 have passed through it. It was not good for me, as it is loud process and my bedroom is right above the room where it is located. So I decided to run the regen process manually, but then I must check once a while screen of the CLACK head to know how much m3 are left there. As I could forget to do that, I had to add somehow this to HA and have a notification, every time X m3 are left and regen is needed. So I came up with this

Notifications in Lovelace


wsoft

Water softener head:

Ingredients needed:

  1. aqara/mijia zigbee window sensors (and integration to HA. I use zigbee2mqtt (best thing ever)). Note: I guess RF window sensors also will do the trick, but I find them super unreliable.
  2. Smart outlet that has power measurement.
  3. Relay 15V (V probably depends on water softener also) ( I had only 5V relay, so I had to add also step down converter, from 15v - 5V)

In my CLACK WS1 motherboard, there is connector for relay with pins RL1;COM+. That is the place we will connect the window sensor. As you can program the head to send signal (in this case 15V to the pins) every time X liters has passed through the softener. In my case, I set the head to send the signal every 10 liters.

To do this, you have to press button together button NEXT and DOWN, till menu appears, then press NEXT till you see RELAY on screen, with UP/DOWN choose set softening and L symbol on screen, press NEXT, set desired amount of liters, press next and set time after how long the signal will be sent to relay.

Solider two wires on Window sensor, where the reed switch is, so when you connect together the wires the signal is sent. Add two wires to from water softener to relay (CHECK POLARITY AND CHECK THE VOLTAGE OF RELAY, AND MESURE BEFORE HOW MUCH V DOES THE WATER SOFTENER GIVE OUT), and from window sensor to normally open relay contacts.
^this was as I did, but probably it must be tweaked as individually needed.

Also the Input select as all other things below is needed to adjust individually.

In short it works like this.

I have set up that after every 4000 liters regen is needed, so it is set in input_number.water_softerner_meter_liters. every time pulse is detected from window sensor it subtracts 10 liters.
When Regeneration is started, my outlet gives me power reading that is largen than 2.8W, as the motor opens and closes the valves, in idle it is not more than 1W. From this I can tell, that cycle started. So in cycle automations it looks for the power above 2.8W and reads the input select selection, so it knows what cycle is running. On next >2.8W spike it knows the next cycle started. Also it sets the timer for every cycle when it starts.

It probably has a lot to improve, but for me it works quite good at the moment, and hey, “it’s not stupid if it works” :smiley:
Be glad to hear what to improve, and maybe this would be useful for someone.

#-----------
#INPUT SELECT
#-----------
water_softener_status:
    name: Water softener status
    options:
      - Backwash 1st
      - Brine
      - Backwash
      - Rinse
      - Fill
      - Idle
    initial: Idle
    
#-----------
#INPUT NUMBER
#-----------
water_softerner_meter_liters: 
    name: Water softener l left
    min: 0
    max: 999999
    step: 10
    unit_of_measurement: l
    mode: box

#-----------
#TIMERS
#-----------
  timer_ws_backwash1:
    name: Backwash 1st
    duration: '0:06:10'
  timer_ws_brine:
    name: Brine
    duration: '0:70:04'
  timer_ws_backwash:
    name: Backwash
    duration: '0:03:03'
  timer_ws_rinse:
    name: Rinse
    duration: '0:04:10'
  timer_ws_fill:
    name: Fill
    duration: '0:13:46'
  timer_ws_total:
    name: Total
    duration: '1:37:40'


#-----------
#SENSORS
#-----------
  - platform: template  
    sensors:
      water_softener_m3_left:
        friendly_name: Water softener m3 left
        unit_of_measurement: 'm3'
        value_template: >
            {{ ((4000 - (states.input_number.water_softerner_meter_liters.state | int))*0.001) | round(2) }}
      water_softener_l_left:
        friendly_name: Water softener l left
        unit_of_measurement: 'l'
        value_template: >
            {{ 4000 - (states.input_number.water_softerner_meter_liters.state | int) }}
      water_softener_regen:
        friendly_name: "Water filter regen needed"
        value_template: > 
           {% set val =  (states.sensor.water_softener_l_left.state | int)  %}
           {% if val > 1000 %}
             False
           {% elif val < 1000 %}
              True
           {% else %}   
              Error
           {% endif %}
        icon_template: >
           {% set val =  (states.sensor.water_softener_l_left.state | int)  %}
           {% if val > 1000 %}
             mdi:beaker
           {% elif val < 1000 %}
              mdi:beaker-alert-outline
           {% else %}   
              mdi:alert-octagram-outline
           {% endif %}   
           

#read power readings from outlet           
  - platform: mqtt
    name: Water softener Power
    state_topic: "tele/son-wsoftener/SENSOR"
    value_template: '{{ value_json["ENERGY"]["Power"] }}'
    unit_of_measurement: "W"
    qos: 1
 

#Read last triggered state of mqtt
  - platform: mqtt
    state_topic: "home/lasttrigger/water_softener"
    name: "water softener last triggered"

#-----------
#SWITCHES
#-----------
  - platform: mqtt
    name: "Water softener outlet"
    state_topic: "stat/son-wsoftener/POWER"
    command_topic: "cmnd/son-wsoftener/POWER"
    qos: 1
    payload_on: "ON"
    payload_off: "OFF"
    retain: false

#-----------
#AUTOMATIONS
#-----------
#pulse automation for aqara sensor
- alias: "Water softener - Pulse Received"
  initial_state: true  
  trigger: 
  - platform: state
    entity_id: binary_sensor.water_softener_pulse_contact
  condition: 
  - condition: state
    entity_id: binary_sensor.water_softener_pulse_contact
    state: 'off'
  action:
  - service: input_number.set_value
    data_template:
      entity_id: input_number.water_softerner_meter_liters
      value: "{{ (states.input_number.water_softerner_meter_liters.state | int ) + 10 }}"
 
#automations for water regen 5 cycles      

#Backwash first
- alias: "Set water softener start Backwash 1st"
  initial_state: true
  trigger:
    - platform: numeric_state
      entity_id: sensor.water_softener_power
      above: 2.8
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: input_select.water_softener_status
        state: Idle
  action:
    - service: input_select.select_option
      data:
        entity_id: input_select.water_softener_status
        option: Backwash 1st
    - service: timer.start
      entity_id: timer.timer_ws_backwash1
    - service: timer.start
      entity_id: timer.timer_ws_total
    - service: input_number.set_value
      data_template:
        entity_id: input_number.water_softerner_meter_liters
        value: 0
        
#Brine        
- alias: "Set water softener start Brine"
  initial_state: true  
  trigger:
    - platform: numeric_state
      entity_id: sensor.water_softener_power
      above: 2.8
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: input_select.water_softener_status
        state: Backwash 1st
  action:
    - service: input_select.select_option
      data:
        entity_id: input_select.water_softener_status
        option: Brine
    - service: timer.start
      entity_id: timer.timer_ws_brine        

#Backwash second
- alias: "Set water softener start backwash"
  initial_state: true  
  trigger:
    - platform: numeric_state
      entity_id: sensor.water_softener_power
      above: 2.8
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: input_select.water_softener_status
        state: Brine 
  action:
    - service: input_select.select_option
      data:
        entity_id: input_select.water_softener_status
        option: Backwash
    - service: timer.start
      entity_id: timer.timer_ws_backwash
        
#Rinse        
- alias: "Set water softener start Rinse"
  initial_state: true  
  trigger:
    - platform: numeric_state
      entity_id: sensor.water_softener_power
      above: 2.8
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: input_select.water_softener_status
        state: Backwash
  action:
    - service: input_select.select_option
      data:
        entity_id: input_select.water_softener_status
        option: Rinse
    - service: timer.start
      entity_id: timer.timer_ws_rinse    

#Fill salt container
- alias: "Set water softener start Fill"
  initial_state: true  
  trigger:
    - platform: numeric_state
      entity_id: sensor.water_softener_power
      above: 2.8
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: input_select.water_softener_status
        state: Rinse
  action:
    - service: input_select.select_option
      data:
        entity_id: input_select.water_softener_status
        option: Fill
    - service: timer.start
      entity_id: timer.timer_ws_fill
        
#Finish cycles with idle state        
- alias: "Set water softener Idle"
  initial_state: true  
  trigger:
    - platform: numeric_state
      entity_id: sensor.water_softener_power
      above: 2.8
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: input_select.water_softener_status
        state: Fill
  action:
    - service: input_select.select_option
      data:
        entity_id: input_select.water_softener_status
        option: Idle
    - service: input_number.set_value
      data_template:
        entity_id: input_number.water_softerner_meter_liters
        value: 10        
    - service: mqtt.publish #publish last triggered state
      data_template:
        topic: "home/lasttrigger/water_softener"
        payload_template: "{{ now().strftime('%d.%b %H:%M') }}"
        retain: True
 
#-----------
#LOVELACE CARDS
#----------- 

#Notification that regeneration is required
        
type: conditional
conditions:
  - entity: sensor.water_softener_regen
    state: 'True'
card:
  type: entities
  style: |
    ha-card {
      --ha-card-background: rgba(200, 0, 0, 0.5);
      color: white
    } 
    .card-content {
      padding: 8px;
    }
    .card-content > div {
      margin: 0 !important;
    }  
    .card-header {
      font-size: 18px;
      padding: 5px 25px;
      font-weight: bold;
    }  
     :host {
       --paper-item-icon-color: white;
       --secondary-text-color: #A9A9A9
  entities:
    - entity: input_number.water_softerner_meter_liters
      type: 'custom:multiple-entity-row'
      icon: 'mdi:beaker-alert-outline'
      name: Water softener
      secondary_info:
        entity: sensor.water_softener_regen
        name: 'Dirty: '
      state_header: used
      entities:
        - entity: sensor.water_softener_last_triggered
          name: last run
        - entity: sensor.water_softener_m3_left
          name: left
        

#Notification when regen is in process with remaining cycle and their times

type: conditional
conditions:
  - entity: timer.timer_ws_total
    state_not: idle
card:
  type: entities
  style: |

    .card-content {
      padding: 8px;
    }
    .card-content > div {
      margin: 0 !important;
    }  
    .card-header {
      font-size: 18px;
      padding: 5px 25px;
      font-weight: bold;
    }  
        .card-header {
          font-size: 18px;
          padding: 5px 25px;
          font-weight: bold;
        }     
  title: Mr. Water Boss working hard
  entities:
    - conditions:
        - entity: timer.timer_ws_backwash1
          state_not: idle
      row:
        entity: timer.timer_ws_backwash1
        icon: 'mdi:numeric-1-circle'
        name: 'Cycle: Backwash #1'
      type: conditional
    - conditions:
        - entity: timer.timer_ws_brine
          state_not: idle
      row:
        entity: timer.timer_ws_brine
        icon: 'mdi:numeric-2-circle'
        name: 'Cycle: Brine'
      type: conditional
    - conditions:
        - entity: timer.timer_ws_backwash
          state_not: idle
      row:
        entity: timer.timer_ws_backwash
        icon: 'mdi:numeric-3-circle'
        name: 'Cycle: Backwash #2'
      type: conditional
    - conditions:
        - entity: timer.timer_ws_rinse
          state_not: idle
      row:
        entity: timer.timer_ws_rinse
        icon: 'mdi:numeric-4-circle'
        name: 'Cycle: Rinse'
      type: conditional
    - conditions:
        - entity: timer.timer_ws_fill
          state_not: idle
      row:
        entity: timer.timer_ws_fill
        icon: 'mdi:numeric-5-circle'
        name: 'Cycle: Fill'
      type: conditional
    - type: section
    - entity: timer.timer_ws_total
      icon: 'mdi:timer-sand'
      name: Total time left (5 cycles)

# card with liters used and m3 left
cards:
  - type: entities
    entities:
      - entity: input_number.water_softerner_meter_liters
        type: 'custom:multiple-entity-row'
        icon: 'mdi:cup-water'
        name: Water softener
        secondary_info:
          entity: input_select.water_softener_status
          name: 'cycle: '
        state_header: l used
        entities:
          - entity: timer.timer_ws_total
            name: time left
          - entity: sensor.water_softener_m3_left
            name: m3 left
    style: |
      ha-card {
        border-radius: 20px
      }
      .card-header {
        font-size: 18px;
        padding: 5px 25px;
        font-weight: bold;
      }          
    title: Water softener
  - entities:
      - entity: sensor.water_softener_l_left
        max: 4000
        min: 0
        name: Liters used
    height: 8px
    decimal: false
    positions:
      icon: 'off'
      indicator: 'off'
      tap_action: info
      name: 'off'
      value: 'off'
    style: |
      ha-card {
        border-radius: 20px
      }
      .card-content {
       padding: 0px 10px 10px 10px;
       }      
    type: 'custom:bar-card'
mode: vertical
type: 'custom:stack-in-card'

5 Likes

no stupid things, man. Really appreciated. I was looking for something like this :slight_smile:

2 Likes

Thanks for posting your project. I have a GW GXSF30H and I have it connected to an ESP8266 to provide water flow data. I want to provide data when it runs the salt cycle. I have tapped into the relay that will trip for each cycle. It triggers for each cycle(in my case called, Fill, Brine, Rinse, Backwash, Fast Rinse). I’m not using a power sensor. Question is, do I need to know how long each cycle lasts? Thanks

I used timer to show in lovelace how much time left on each cycle and how much time left till finish, but you can use it without timer. If you are not using power sensor, how ESP will now that salt cycle has started?

I have created a binary sensor that trips on the water softeners relay that follows the cam wheel that indicates the cycle it’s in. It will trip 5 times I believe. This signal comes from the ESP8266 device and I have verified it works. I need to verify how many times it trips during the regen cycle. I may need a timer for that last cycle to indicate when the last cycle has finished. The ESP monitors 2 signals…water flow and regen cam wheel.

Works also with 2022.11 update water usage in energy dashboard:

add new input_number, create new template sensor and add action to existing automation:

template.yaml

- sensor:
    - name: Water softener m3 total
      unit_of_measurement: "m³"
      device_class: water
      state_class: total_increasing
      state: >
        {{ (((states.input_number.water_softerner_total.state | int))*0.001) | round(2) }}

input_number.yaml

water_softerner_total:
  name: Water softener total l
  min: 0
  max: 9999999
  #step: 0.001
  #    step: 0.010
  step: 10
  unit_of_measurement: l
  mode: box

automations.yaml

##add set_value to newly created input number for existing pulse recieved autiomation.

- alias: "Water softener - Pulse Received"
  initial_state: true
  trigger:
    - platform: state
      entity_id: binary_sensor.water_softener_pulse_contact
  condition:
    - condition: state
      entity_id: binary_sensor.water_softener_pulse_contact
      state: "off"
  action:
    - service: input_number.set_value
      data_template:
        entity_id: input_number.water_softerner_meter_liters
        value: "{{ (states.input_number.water_softerner_meter_liters.state | int ) + 10 }}"
    - service: input_number.set_value
      data_template:
        entity_id: input_number.water_softerner_total
        value: "{{ (states.input_number.water_softerner_total.state | int ) + 10 }}"

Have you try to use the 3 wire meter in the down-right corner of the board? (red-black-white)

google it I found meter’s specification 102 Ipm accuracy +/-5%

1 Like

Just for the information. I have this water softener head. And I try with the connection of the meter, It’s work fantastic. Just use the black and the white cable. The white is the pulse and the black of course the gnd. The red is the 5v. So no need to feed the sensor with the ESP module 5v. I just plug the cable in parallel. I have the reading of liter or gallon / min. With 62 pulse, it’s 1 gallon.

sensor:
  - platform: pulse_counter
    pin: GPIO5
    unit_of_measurement: 'gal/min'
    accuracy_decimals: 1
    update_interval: 5s
    name: 'Water Meter House'
    filters:
    - lambda: return (x / 62.0);  
    
    total:
      unit_of_measurement: 'gal'
      name: 'Water Meter Total'
      state_class: total_increasing
      device_class: water
      accuracy_decimals: 1
      filters:
      - lambda: return (x / 62.0);
2 Likes

Thanks for sharing it! Can I ask where did you find " 62 impulse=1gallon" ? Is it a specific data or did you just test it? (Opening the water and counting the Impulse?) I would like to do the same but in liter or m^3. Thanks

Thank you for posting this solution. I am just a beginner, can you please share more details on how exactly you did this? Did you still use the relay without the step down converter or did you plug the Aqara sensor directly into the meter connector?

Hi Metus.

First I was start with information in the documentation of Clack flow meter that I found in the compagnie web site. That’s said 37 pulse. https://clackvalves.net/files/8813/8765/9873/Inline_Flow_Meters.pdf But that’s not the same flow meter. So I was try with that, and I was able to see the flow meter data live on the head of the water softener and on my entitie on home assistant. With some try and error I was finished with 62. And for now. that’s fine, the data match perfectly. So I think you can just make the conversion gallon → liter. I put my data in home assistant in gallon. But I’m in Canada. So normaly is the metric system here. So in my Energy Dashboard, Home assistant put the data in liter. I think home assistant do the math. :slight_smile:

Hi Paulv1999.

I’m a beginner too… So don’t worry.

I not use the first method of kpcz. That’s a brilliant idea. But at that time I didn’t have the relay or the step down converter. So I see the post of metus, and I decided to try the head flow meter. I started with a simple code in arduino on a prototype board. And then I found some code on different group to convert to esphome. I finally used a D1 wemo.

You have to use the flow meter on your head like a pulse meter.

It’s very simple code and cable stuff. Use Esphome.



The other cable on the D1 that’s for my meter of salt.


The installation is temporary, I will make my little boxes to protect everything, but for now I wanted to confirm that everything was going to work.


thanks a lot. Only for information in my case the voltage between red and black wire is 4.8V and I don’t know why is not enough to turn on my esp8266 nodemcu board: if I connect it the voltage between red black wires become 2.8V and the flow meter does not work (0 liter/minute on the display fo CLACK WS1 valve) also if the water is flowing and esp8266 does not turn on… if I disconnect black and red wires from esp8266 the flow meter CLACK’s display works great. So I think that not all the esp8266 can be powered from black and red wires of the meter. If I power esp8266 by usb it turn on but with ONLY the white wire connected to pin D1 the impulses are wrong… a lot of liter or impulse or gallons also if there is no flow… so I think the problem is the difference of ground from usb and valve… so for now I’m not able to replicate… maybe I will try with a differente esp8266 like “D1 mini wemo”.

Don’t use the 5v of the Clack head. Me I connected my esp8266 with the usb adaptor 5v for powering the esp module. Just use the black and the white cable of the meter plug.

Wiring code

Clack Head ---------- ESP8266

RED ----------> None;
Black -----------> GND
White. -----------> D15/D3 (GPIO5). (If you taken my code). (On the D1 Wemo WROOM)

Hope it’s help you.

thank you very much, that was helpful. I will give it a try.

Yes probably it will fix the problem, I didn’t it because I’m not sure is “ok” to connect ground to the valve to ground from usb… I know that GND is GND but I’m not sure is “safe” to put together gnd from different device with different power supply (yes both are connect to the same house grid line, but with different converter from AC to DC: one inside valve and one from wall usb charger) I don’t know if I have explained well my concern… However I will try :grinning:

Hi there,
I’m looking at installing this valve and doing some prep-work to be able to connect it.
could you point me to your code for the Wemos d1 ?

Also, do you power your Wemos from the valve, or do you have dedicated power source ?
(from pictures I see red wire seems also to go to the valve)

And how do you get the salt level ?

Hi. its not wemos, it is just a relay, with wemos pinout. (I had just this type laying around) so when it gets signal from head, it closes and opens relay, that opens and closes the reed switch of the aqara door sesonr. So the only power needded is battery to power the aquara sensor.

so there is no code, only the configuration provided here for Home assistant.

Just wanted to say “THANK YOU” for your work on this. My Hellenbrand softener has an identical controller board, and I’ve been trying to figure out how to determine when water is flowing through it in order to control a chlorine injection pump. The system was installed by the previous owners of my house, and part of it involves injecting chlorine to kill the stinky bacteria in the well water. The issue I was trying to solve was the chlorine pump was tied to the well pump, which isn’t generally done these days since it can cause the chlorine pump to run more than it needs to. I now have a Wemos D1 Mini monitoring the water flow from the softener and can automatically switch a 10amp relay for the chlorine pump. Your wiring diagram and code helped me to finally get this all working.

1 Like

thanks for this! Did you ever try to figure out what COMM socket is for and how to control CLACK better? There must be interface that can give more information what actually happens in CLACK. Usage of relays is good and it helps. UNless COMM is to do some remote programming of cycles only? Also, there ar emore options for RELAY in my case. I may have different version of CLACK:

• Set Time on: Relay activates after a set time at the beginning of a
regeneration cycle and then deactivates after a set period of time. The
start of regeneration is defined as the first backwash cycle or Dn brine
cycle, whichever comes fi rst.
• Set L Softening on: Relay activates after a set volume has been used
while in service, then deactivates after the meter stops registering fl ow and the set time period has
expired.
• Set L Softening Regen on: Relay activates after a set volume has been used while in service or
during regeneration, then deactivates after the meter stops registering fl ow and the set time period
has expired.

Did you test REGEN options with RELAY? Doesn’t it provide more updates when cycle runs? maybe then you don’t need to measure power and manually capture details of timing of each cycle?

thanks