├── .DS_Store ├── README ├── diagram.png ├── printje.jpg ├── min_max_NL.jpg ├── aansluitingen.JPG ├── Printscreen_EN.jpg ├── Printscreen_NL.jpg ├── README.md ├── Clack INSTLKRT_V3_NL.pdf ├── Full-CLACKWS1-Manual.pdf ├── aansluitingen_print.jpg ├── R_EN.md └── R_NL.md ├── www └── images │ ├── softener.png │ ├── softener0.png │ ├── softener10.png │ ├── softener100.png │ ├── softener20.png │ ├── softener40.png │ ├── softener60.png │ └── softener80.png ├── esphome ├── secrets.yaml ├── .clack-labels-en.yaml ├── .clack-labels-nl.yaml ├── distance-sensor2.h ├── board-esp8266.yaml ├── board-esp32.yaml ├── board-esp32s3.yaml ├── board-esp32-wemos-s3.yaml └── clack.yaml ├── .github └── workflows │ └── build.yml ├── README.md └── home_assistant ├── clack_en.yaml ├── clack_nl.yaml ├── lovelace_menu_nl.yaml └── lovelace_menu_en.yaml /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/.DS_Store -------------------------------------------------------------------------------- /README/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/README/diagram.png -------------------------------------------------------------------------------- /README/printje.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/README/printje.jpg -------------------------------------------------------------------------------- /README/min_max_NL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/README/min_max_NL.jpg -------------------------------------------------------------------------------- /README/aansluitingen.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/README/aansluitingen.JPG -------------------------------------------------------------------------------- /www/images/softener.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/www/images/softener.png -------------------------------------------------------------------------------- /www/images/softener0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/www/images/softener0.png -------------------------------------------------------------------------------- /README/Printscreen_EN.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/README/Printscreen_EN.jpg -------------------------------------------------------------------------------- /README/Printscreen_NL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/README/Printscreen_NL.jpg -------------------------------------------------------------------------------- /www/images/softener10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/www/images/softener10.png -------------------------------------------------------------------------------- /www/images/softener100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/www/images/softener100.png -------------------------------------------------------------------------------- /www/images/softener20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/www/images/softener20.png -------------------------------------------------------------------------------- /www/images/softener40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/www/images/softener40.png -------------------------------------------------------------------------------- /www/images/softener60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/www/images/softener60.png -------------------------------------------------------------------------------- /www/images/softener80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/www/images/softener80.png -------------------------------------------------------------------------------- /README/README.md: -------------------------------------------------------------------------------- 1 | # Readme 2 | 3 | ## Dutch: 4 | [README](R_NL.md) 5 | 6 | ## English: 7 | 8 | [README](R_EN.md) -------------------------------------------------------------------------------- /README/Clack INSTLKRT_V3_NL.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/README/Clack INSTLKRT_V3_NL.pdf -------------------------------------------------------------------------------- /README/Full-CLACKWS1-Manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/README/Full-CLACKWS1-Manual.pdf -------------------------------------------------------------------------------- /README/aansluitingen_print.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fonske/clack-reader/HEAD/README/aansluitingen_print.jpg -------------------------------------------------------------------------------- /esphome/secrets.yaml: -------------------------------------------------------------------------------- 1 | # Your Wi-Fi SSID and password 2 | wifi_ssid: "TestWifi" 3 | wifi_password: "TestWifiSecret" 4 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build ESPHome firmware 2 | 3 | # Controls when the action will run. Triggers the workflow on push 4 | on: 5 | push: 6 | pull_request: 7 | release: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | name: "Build" 13 | steps: 14 | - name: "Checkout" 15 | uses: actions/checkout@v3 16 | - name: "Create secrets file" 17 | run: | 18 | touch esphome/secrets.yaml 19 | cat < esphome/secrets.yaml 20 | wifi_ssid: TestWifi 21 | wifi_password: TestWifiSecret 22 | EOF 23 | - name: "Build" 24 | uses: esphome/build-action@v1 25 | id: esphome-build 26 | with: 27 | yaml_file: esphome/clack.yaml 28 | -------------------------------------------------------------------------------- /esphome/.clack-labels-en.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | clack_distance: Salt level distance 3 | clack_procent: Salt level percent 4 | clack_height: Salt level height 5 | clack_watermeter_total: Water meter 6 | clack_m3_left: Water softener m3 left 7 | clack_l_left: Water softener ltr left 8 | clack_version: Version 9 | clack_regeneration_last: Water softener regenerated on 10 | clack_fill_salt: Fill salt 11 | clack_saltlevel_height_min: Min salt distance 12 | clack_saltlevel_height_max: Max salt distance 13 | clack_saltlevel_height_fill: Fill salt distance 14 | clack_capacity_liters: Capacity in liters 15 | clack_capacity_days: Capacity in days 16 | clack_watermeter_pulse: Watermeter pulse 17 | clack_regeneration_pulse: Regeneration pulse 18 | clack_ip: Water softener IP 19 | clack_wifi_signal_db: WiFi Signal dB 20 | clack_wifi_signal_db_percent: WiFi Signal 21 | clack_uptime: Uptime 22 | hours: hours 23 | days: days 24 | clack_yes: "yes" 25 | clack_no: "no" 26 | 27 | text_sensor: 28 | # Expose last regeneration information as sensor / already in English 29 | - platform: template 30 | name: ${clack_regeneration_last} 31 | id: clack_regeneration_last 32 | icon: mdi:clock-start 33 | update_interval: never 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clack-reader 2 | Printed circuit board to read out a Clack WS1CK watersoftener with ultrasonic sensor and pulse relais of the WS1. 3 | 4 | See README directory for more information on how to set this up and connect. 5 | 6 | # Platforms 7 | Currently supported ESP32 (wemos d32 mini), ESP32S3 (lilygo S3-T7), ESP32 S3 (wemos S3 mini) and ESP8266 (wemos d1 mini) platforms. 8 | By default ESP32 S3 mini is used. If you want to use ESP8266 for example, edit file `esphome/clack.yaml`, comment out esp32 include and uncomment esp8266 include file. 9 | 10 | ``` 11 | packages: 12 | remote_package: 13 | url: https://github.com/fonske/clack-reader 14 | ref: main 15 | refresh: 0s 16 | files: [ esphome/.clack-labels-nl.yaml, esphome/board-esp32-wemos-s3.yaml ] 17 | ## choices are: esphome/.clack-labels-en.yaml, esphome/.clack-labels-nl.yaml 18 | ## esphome/board-esp32.yaml, esphome/board-esp32s3.yaml, 19 | ## esphome/board-esp32-wemos-s3.yaml, esphome/board-esp8266.yaml 20 | 21 | ## for developing/testing, uncomment local includes and comment out above remote_package packages part. 22 | #packages: 23 | # substitutions: !include .clack-labels-en.yaml 24 | # substitutions: !include .clack-labels-nl.yaml 25 | # device_base1: !include board-esp32.yaml 26 | # device_base1: !include board-esp32s3.yaml 27 | # device_base1: !include board-esp32-wemos-s3.yaml 28 | # device_base1: !include board-esp8266.yaml 29 | ``` 30 | 31 | # Translations 32 | Currently supported languages are en, nl. 33 | In order to change language, edit file `esphome/clack.yaml`, and change include file (esphome-/.clack-labels-.yaml) 34 | 35 | ## end_of_life 36 | This project is not longer maintained. Go to Clack reader V4 for a newer design of the clack reader. 37 | -------------------------------------------------------------------------------- /esphome/.clack-labels-nl.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | clack_distance: Zoutniveau afstand 3 | clack_procent: Zoutniveau procent 4 | clack_height: Zoutniveau hoogte 5 | clack_watermeter_total: Watermeter 6 | clack_m3_left: Waterontharder m3 over 7 | clack_l_left: Waterontharder ltr over 8 | clack_version: Versie 9 | clack_regeneration_last: Waterontharder geregenereerd op 10 | clack_fill_salt: Zout bijvullen 11 | clack_saltlevel_height_min: Min afstand zout 12 | clack_saltlevel_height_max: Max afstand zout 13 | clack_saltlevel_height_fill: Zout bijvullen afstand 14 | clack_capacity_liters: Capaciteit in liters 15 | clack_capacity_days: Capaciteit in dagen 16 | clack_watermeter_pulse: Watermeter pulse 17 | clack_regeneration_pulse: Regeneratie pulse 18 | clack_ip: Waterontharder IP 19 | clack_wifi_signal_db: WiFi Signaal dB 20 | clack_wifi_signal_db_percent: WiFi Signaal 21 | clack_uptime: Uptime 22 | hours: uur 23 | days: dagen 24 | clack_yes: ja 25 | clack_no: nee 26 | 27 | text_sensor: 28 | # Expose last regeneration information as sensor 29 | - platform: template 30 | name: ${clack_regeneration_last} 31 | id: clack_regeneration_last 32 | icon: mdi:clock-start 33 | update_interval: never 34 | filters: 35 | - substitute: 36 | - "Jan -> jan" 37 | - "Feb -> feb" 38 | - "Mar -> mar" 39 | - "Apr -> apr" 40 | - "Mai -> mei" 41 | - "Jun -> jun" 42 | - "Jul -> jul" 43 | - "Aug -> aug" 44 | - "Sep -> sep" 45 | - "Okt -> okt" 46 | - "Nov -> nov" 47 | - "Dec -> dec" 48 | - "Mon -> maa" 49 | - "Tue -> din" 50 | - "Wed -> woe" 51 | - "Thu -> don" 52 | - "Fri -> vri" 53 | - "Sat -> zat" 54 | - "Sun -> zon" -------------------------------------------------------------------------------- /esphome/distance-sensor2.h: -------------------------------------------------------------------------------- 1 | #include "esphome.h" 2 | using namespace esphome; 3 | 4 | enum statesRX 5 | { 6 | ST_RX_HEADER=0, 7 | ST_RX_DATA, 8 | ST_RX_PROCESSMSG 9 | }; 10 | 11 | unsigned char data[4]={}; 12 | //float distance; 13 | 14 | class DistanceSensor : public PollingComponent, public sensor::Sensor, public UARTDevice{ 15 | public: 16 | DistanceSensor(uint32_t update_interval, UARTComponent *parent) : PollingComponent(update_interval), UARTDevice(parent) {} 17 | 18 | void setup() override{}; 19 | 20 | void update() override { 21 | static uint8_t 22 | stateRX = ST_RX_HEADER, 23 | rxIdx; 24 | 25 | if( available() > 0 ) 26 | { 27 | do 28 | { 29 | uint8_t ch = read(); 30 | switch( stateRX ) 31 | { 32 | case ST_RX_HEADER: 33 | if( ch == 0xff ) 34 | { 35 | rxIdx = 0; 36 | data[rxIdx++] = ch; 37 | stateRX = ST_RX_DATA; 38 | 39 | }//if 40 | 41 | break; 42 | 43 | case ST_RX_DATA: 44 | data[rxIdx++] = ch; 45 | if( rxIdx == 4 ) 46 | stateRX = ST_RX_PROCESSMSG; 47 | break; 48 | 49 | case ST_RX_PROCESSMSG: 50 | uint8_t sum = 0; 51 | for( uint8_t i=0; i<3; i++ ) 52 | sum = sum + data[i]; 53 | 54 | if( sum == data[3] ) 55 | { 56 | uint16_t distance = ((uint16_t)data[1] << 8) + data[2]; 57 | if( distance > 30 ) 58 | { 59 | publish_state(distance/10); 60 | }//if 61 | else 62 | publish_state(0); 63 | 64 | }//if 65 | else 66 | ESP_LOGD("custom", "Msg checksum error."); 67 | 68 | stateRX = ST_RX_HEADER; 69 | 70 | break; 71 | 72 | }//switch 73 | 74 | }while( available() > 0 ); 75 | 76 | }//if 77 | 78 | }//loop 79 | }; 80 | 81 | -------------------------------------------------------------------------------- /README/R_EN.md: -------------------------------------------------------------------------------- 1 | # Clack - Reader 2 | 3 | ## Lovelace menu 4 | In order to use the front-end as shown here: 5 | ![Example](Printscreen_EN.jpg) 6 | 7 | You will need to install HACS and the following plugins: 8 | 9 | * stack-in-card 10 | * multiple-entity-row 11 | * bar-card 12 | * apexcharts (Bar Charts) 13 | 14 | ## automations and sensor 15 | Add the content of [clack_en.yaml](../clack_en.yaml) to your current configuration file in Home Assistant. 16 | Or better: 17 | 18 | ### Custom file location: 19 | If you want to keep the file seperate from your config file you can include them like so: 20 | 21 | ```yml 22 | homeassistant: 23 | packages: !include_dir_named packages 24 | ``` 25 | Now you can create a folder called `packages` in the folder `config` and place the `clack_en.yaml` there. 26 | 27 | Make sure to restart HomeAssistant. 28 | 29 | ## Configuration 30 | ### clack_en.yaml 31 | You will need to time your clack head (with a stopwatch) and adjust the times in the `clack_EN.yaml` to the time your clack actually takes per step. 32 | 33 | You can see the status of the steps on the display. 34 | 35 | ### Pictures salt tank 36 | In order to get the salt tank level to display you will need to copy the pictures in the `/www/images` directory to your local `/www/images` directory. 37 | 38 | ### Relays 39 | The 2 relays that the clack head has still need to be set-up. 40 | * Relay1: Counting of water usage 41 | * Relay2: Regeneration pulse 42 | 43 | You can see on the back of the circuit board where to hook each wire up to makred as `RLY1`, `+COM` and `RLY2` for this to work these need to be connected in the srew terminals on the right side of the Clack board. 44 | ![Schematic](diagram.png) 45 | 46 | ### Relay Config 47 | Extra document (still in dutch sorry) with info can be found here: [Settings PDF](instelkaart%20clack%20ws1.pdf) or the full english manual here: [Manual](Full-CLACKWS1-Manual.pdf) 48 | 49 | 1. Press `arrow down` and the `next` button for 5 secconds 50 | 2. Press next (softening) is now visible 51 | 3. press the `next` button till you see `` Thange this to `ON` (softening L) 52 | 4. Press `next` 53 | 5. Set the value to `2 L` (this gives a pulse every 2 liters) 54 | 5. Press `next` 55 | 6. set time: 0.01 min 56 | 7. Press `next` 57 | 8. set `rlY 2` "time" to on (gives a pulse when regeneration starts) 58 | 9. Press `next` 59 | 10. set time: 0.01 min 60 | 11. press next 2 times and you are done 61 | 62 | Good Luck! 63 | 64 | ## Note: 65 | Mounting the circuitboard with ESP in the Clack housing can be tricky. 66 | To be able to close the Clack reader the Circuitboard will point slightly inwards. 67 | 68 | The ESP might come loose when attempting to close the clack head. 69 | 70 | Update: with the use of the smaller wemos s3 mini, this is not a problem anymore. 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /README/R_NL.md: -------------------------------------------------------------------------------- 1 | # Clack - Lezer 2 | 3 | ## Lovelace menu 4 | Om het lovelace menu volledig te benutten dient via hacs (frontend) 5 | de volgende repositories geinstalleerd te worden (verkennen en downloaden) 6 | 7 | Voorbeeld dahsboard: 8 | ![Example](Printscreen_NL.jpg) 9 | 10 | * stack-in-card 11 | * multiple-entity-row 12 | * bar-card 13 | * apexcharts (staafdiagram) 14 | 15 | ## Automations en sensor(s) 16 | [clack.yaml](../clack.yaml) samenvoegen met configuration.yaml of beter: 17 | 18 | ### Bestand op eigen lokatie: 19 | [clack.yaml](../clack.yaml) op een eigen lokatie zetten: 20 | configuration.yaml aanpassen naar: 21 | 22 | ```yml 23 | homeassistant: 24 | packages: !include_dir_named packages 25 | ``` 26 | 27 | Dan directory /packages aanmaken in /config en daar de clack.yaml in kopieren 28 | HA opnieuw starten 29 | 30 | ## Configuratie 31 | ### Clack.yaml 32 | In clack.yaml moeten de tijden nog aangepast worden aan je eigen tijden (timer) voor de simulatie van het regenereren in HA. 33 | Even met een stopwatch ofzo, nadat de regeneratie handmatig gestart is. Elke keer dat de inwendige schuif beweegt is een stap (zie ook op het display vd clack) 34 | Het kan zijn, dat je clack 5 cyclussen heeft ipv 4. Backwash, brine, backwash, rinse, fill. In de code is de 2e backwash eruit gehaald, wat het meest gangbaar is, voor de meeste ontharders. Anders kan je een timer toevoegen en de code wat aanpassen in clack.yaml 35 | 36 | Bijgevoegd ook de plaatjes voor de simulatie van het zoutniveau: 37 | naar /www/images kopieren 38 | 39 | ### Relais configuratie 40 | De werking van de 2 relays moeten nog in de clack ingesteld worden: 41 | * Relay 1 is voor de waterpulsen te tellen tijdens normale werking 42 | * Relay 2 is voor eenmalig een puls te geven wanneer de ontharder regenereerd 43 | Achter op de print staat welk draadje voor wat is om aan de relays aan te sluiten (de 3 aderige stekkerblok) 44 | ![aansluitingen](diagram.png) 45 | 46 | Instellen: [Settings PDF](instelkaart%20clack%20ws1.pdf) Volledige handleiding in Engels: [Manual](Full-CLACKWS1-Manual.pdf) 47 | 1. next + pijltje omlaag -> 5 sec vasthouden 48 | 2. next (softening) is dan zichtbaar 49 | 3. doordrukken op next tot Deze op ON zetten (softening L) 50 | 4. next 51 | 5. Dan op 2 L zetten (elke flowmeter puls is dan 2 ltr) 52 | 6. next 53 | 7. set time: 0.01 min 54 | 8. next 55 | 9. set rlY 2 "time" to on (geeft dan een puls bij regeneratie start) 56 | 10. next 57 | 11. set time: 0.01 min 58 | 12. 2x next en klaar 59 | 60 | Succes! 61 | 62 | ## Noot: 63 | Het monteren van de esp print in de behuizing is wel wat lastig. 64 | De ESP print steekt achter de rand naar binnen, van de clack behuizing zodat deze weer gesloten kan worden met de kap. 65 | Soms wil het esp printje uit de pinnen komen. (iets of wat speling mag wel) 66 | 67 | Update: met een wemos s3 mini is dit probleem verholpen. Deze is wat kleiner. 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /esphome/board-esp8266.yaml: -------------------------------------------------------------------------------- 1 | ### ESP used is a Wemos d1 mini 2 | 3 | esp8266: 4 | board: nodemcuv2 5 | 6 | uart: 7 | id: uart_bus 8 | tx_pin: 4 #D2 9 | rx_pin: 5 #D1 10 | baud_rate: 9600 11 | 12 | # Enable/Disable logging - ESP8266 is low on memory, so logger is disabled by default 13 | # logger: 14 | # baud_rate: 0 # <--- super important! for ESP8266 15 | 16 | # captative portal and webserver is disabled for ESP8266 due low RAM. 17 | # if enabled, it leads to unstable operation, Wifi disconnects, etc. 18 | # web_server: 19 | # port: 80 20 | 21 | ## watermeter pulse / relay 1 22 | binary_sensor: 23 | - platform: gpio 24 | pin: 25 | number: 2 # D4 26 | inverted: true 27 | mode: 28 | input: true 29 | pullup: true 30 | id: clack_watermeter_pulse 31 | name: ${clack_watermeter_pulse} 32 | # icon: mdi:toggle-switch-variant 33 | filters: 34 | - delayed_on_off: 50ms 35 | on_press: 36 | then: 37 | - sensor.template.publish: 38 | id: clack_watermeter 39 | state: !lambda |- 40 | return id(totalWaterUsage) += 2; 41 | - sensor.template.publish: 42 | id: clack_m3_left 43 | state: !lambda |- 44 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 45 | - sensor.template.publish: 46 | id: clack_l_left 47 | state: !lambda |- 48 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 49 | 50 | ## regeneration pulse / relay 2 51 | - platform: gpio 52 | pin: 53 | number: 14 #D5 54 | inverted: true 55 | mode: 56 | input: true 57 | pullup: true 58 | id: clack_regeneration_pulse 59 | name: ${clack_regeneration_pulse} 60 | # icon: mdi:toggle-switch-variant 61 | filters: 62 | - delayed_on_off: 800ms 63 | on_press: 64 | then: 65 | - globals.set: 66 | id: totalWaterUsage 67 | value: '00' 68 | - text_sensor.template.publish: 69 | id: clack_regeneration_last 70 | state: !lambda |- 71 | char str[32]; 72 | time_t currTime = id(clack_sntp_time).now().timestamp; 73 | strftime(str, sizeof(str), "%a %d %b %H:%M", localtime(&currTime)); 74 | return { str }; 75 | - sensor.template.publish: 76 | id: clack_watermeter 77 | state: !lambda |- 78 | return id(totalWaterUsage); 79 | - sensor.template.publish: 80 | id: clack_m3_left 81 | state: !lambda |- 82 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 83 | - sensor.template.publish: 84 | id: clack_l_left 85 | state: !lambda |- 86 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 87 | 88 | button: 89 | ## temporarely test button for testing reg puls 90 | - id: clack_use_test_button 91 | name: Test button use pulse 92 | platform: template 93 | on_press: 94 | then: 95 | - sensor.template.publish: 96 | id: clack_watermeter 97 | state: !lambda |- 98 | return id(totalWaterUsage) += 2; 99 | - sensor.template.publish: 100 | id: clack_m3_left 101 | state: !lambda |- 102 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 103 | - sensor.template.publish: 104 | id: clack_l_left 105 | state: !lambda |- 106 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 107 | - lambda: |- 108 | ESP_LOGI("UseTest", "button pressed"); 109 | 110 | ## temporarely test button for testing reg puls 111 | - id: clack_reg_test_button 112 | name: Test button reg pulse 113 | platform: template 114 | on_press: 115 | then: 116 | - globals.set: 117 | id: totalWaterUsage 118 | value: '00' 119 | - text_sensor.template.publish: 120 | id: clack_regeneration_last 121 | state: !lambda |- 122 | char str[32]; 123 | time_t currTime = id(clack_sntp_time).now().timestamp; 124 | strftime(str, sizeof(str), "%a %d %b %H:%M", localtime(&currTime)); 125 | return { str }; 126 | - sensor.template.publish: 127 | id: clack_watermeter 128 | state: !lambda |- 129 | return id(totalWaterUsage); 130 | - sensor.template.publish: 131 | id: clack_m3_left 132 | state: !lambda |- 133 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 134 | - sensor.template.publish: 135 | id: clack_l_left 136 | state: !lambda |- 137 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 138 | - lambda: |- 139 | ESP_LOGI("RegTest", "button pressed"); -------------------------------------------------------------------------------- /esphome/board-esp32.yaml: -------------------------------------------------------------------------------- 1 | ### ESP32 used is a MH-ET-LIVE, also known as Wemos D32 Mini 2 | ### https://www.bitsandparts.nl/MH-ET-Live-MiniKit-ESP32-WiFi-Buetooth-ontwikkelboard-p1905277 3 | 4 | esp32: 5 | board: mhetesp32minikit 6 | framework: 7 | type: arduino 8 | 9 | uart: 10 | id: uart_bus 11 | tx_pin: 21 12 | rx_pin: 22 13 | baud_rate: 9600 14 | 15 | # Enable/Disable logging 16 | logger: 17 | logs: 18 | modbus_controller.sensor: WARN 19 | modbus_controller.output: WARN 20 | modbus.number: WARN 21 | esp32.preferences: WARN 22 | sensor: WARN 23 | text_sensor: WARN 24 | dht.sensor: WARN 25 | switch: WARN 26 | button: WARN 27 | number: WARN 28 | # baud_rate: 0 # <--- super important! for ESP8266 29 | 30 | wifi: 31 | ap: 32 | ssid: "${name} hotspot" 33 | password: "configesp" 34 | 35 | captive_portal: 36 | 37 | # Enable Web server. 38 | web_server: 39 | port: 80 40 | 41 | ## watermeter pulse / relay 1 42 | binary_sensor: 43 | - platform: gpio 44 | pin: 45 | number: 16 # mh-et-live: 16, wemos d1 mini -D4 46 | inverted: true 47 | mode: 48 | input: true 49 | pullup: true 50 | id: clack_watermeter_pulse 51 | name: ${clack_watermeter_pulse} 52 | # icon: mdi:toggle-switch-variant 53 | filters: 54 | - delayed_on_off: 50ms 55 | on_press: 56 | then: 57 | - sensor.template.publish: 58 | id: clack_watermeter 59 | state: !lambda |- 60 | return id(totalWaterUsage) += 2; 61 | - sensor.template.publish: 62 | id: clack_m3_left 63 | state: !lambda |- 64 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 65 | - sensor.template.publish: 66 | id: clack_l_left 67 | state: !lambda |- 68 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 69 | 70 | ## regeneration pulse / relay 2 71 | - platform: gpio 72 | pin: 73 | number: 18 # mh-et-live: 18, wemos d1 mini -D5 74 | inverted: true 75 | mode: 76 | input: true 77 | pullup: true 78 | id: clack_regeneration_pulse 79 | name: ${clack_regeneration_pulse} 80 | # icon: mdi:toggle-switch-variant 81 | filters: 82 | - delayed_on_off: 800ms 83 | on_press: 84 | then: 85 | - globals.set: 86 | id: totalWaterUsage 87 | value: '00' 88 | - text_sensor.template.publish: 89 | id: clack_regeneration_last 90 | state: !lambda |- 91 | char str[32]; 92 | time_t currTime = id(clack_sntp_time).now().timestamp; 93 | strftime(str, sizeof(str), "%a %d %b %H:%M", localtime(&currTime)); 94 | return { str }; 95 | - sensor.template.publish: 96 | id: clack_watermeter 97 | state: !lambda |- 98 | return id(totalWaterUsage); 99 | - sensor.template.publish: 100 | id: clack_m3_left 101 | state: !lambda |- 102 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 103 | - sensor.template.publish: 104 | id: clack_l_left 105 | state: !lambda |- 106 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 107 | 108 | button: 109 | ## temporarely test button for testing reg puls 110 | - id: clack_use_test_button 111 | name: Test button use pulse 112 | platform: template 113 | on_press: 114 | then: 115 | - sensor.template.publish: 116 | id: clack_watermeter 117 | state: !lambda |- 118 | return id(totalWaterUsage) += 2; 119 | - sensor.template.publish: 120 | id: clack_m3_left 121 | state: !lambda |- 122 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 123 | - sensor.template.publish: 124 | id: clack_l_left 125 | state: !lambda |- 126 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 127 | - lambda: |- 128 | ESP_LOGI("UseTest", "button pressed"); 129 | 130 | ## temporarely test button for testing reg puls 131 | - id: clack_reg_test_button 132 | name: Test button reg pulse 133 | platform: template 134 | on_press: 135 | then: 136 | - globals.set: 137 | id: totalWaterUsage 138 | value: '00' 139 | - text_sensor.template.publish: 140 | id: clack_regeneration_last 141 | state: !lambda |- 142 | char str[32]; 143 | time_t currTime = id(clack_sntp_time).now().timestamp; 144 | strftime(str, sizeof(str), "%a %d %b %H:%M", localtime(&currTime)); 145 | return { str }; 146 | - sensor.template.publish: 147 | id: clack_watermeter 148 | state: !lambda |- 149 | return id(totalWaterUsage); 150 | - sensor.template.publish: 151 | id: clack_m3_left 152 | state: !lambda |- 153 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 154 | - sensor.template.publish: 155 | id: clack_l_left 156 | state: !lambda |- 157 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 158 | - lambda: |- 159 | ESP_LOGI("RegTest", "button pressed"); -------------------------------------------------------------------------------- /esphome/board-esp32s3.yaml: -------------------------------------------------------------------------------- 1 | ### ESP32S3 used is a Lilygo T7-S3 2 | ### https://www.tindie.com/products/lilygo/lilygo-t7-s3-esp32-s3-development-board/ 3 | 4 | esp32: 5 | board: adafruit_feather_esp32s3_nopsram 6 | framework: 7 | type: arduino 8 | 9 | uart: 10 | id: uart_bus 11 | tx_pin: 13 12 | rx_pin: 14 13 | baud_rate: 9600 14 | 15 | status_led: 16 | pin: 17 | number: 17 18 | 19 | # get rid of CDC error 20 | esphome: 21 | platformio_options: 22 | board_build.extra_flags: 23 | - "-DARDUINO_USB_CDC_ON_BOOT=0" 24 | 25 | # Enable/Disable logging 26 | logger: 27 | logs: 28 | modbus_controller.sensor: WARN 29 | modbus_controller.output: WARN 30 | modbus.number: WARN 31 | esp32.preferences: WARN 32 | sensor: WARN 33 | text_sensor: WARN 34 | dht.sensor: WARN 35 | switch: WARN 36 | button: WARN 37 | number: WARN 38 | # baud_rate: 0 # <--- super important! for ESP8266 39 | 40 | wifi: 41 | ap: 42 | ssid: "${name} hotspot" 43 | password: "configesp" 44 | 45 | captive_portal: 46 | 47 | # Enable Web server. 48 | web_server: 49 | port: 80 50 | 51 | ## watermeter pulse / relay 1 52 | binary_sensor: 53 | - platform: gpio 54 | pin: 55 | number: 12 # lilygo ESP32S3 T7-S3: 12-1, mh-et-live: 16, wemos d1 mini -D4 56 | inverted: true 57 | mode: 58 | input: true 59 | pullup: true 60 | id: clack_watermeter_pulse 61 | name: ${clack_watermeter_pulse} 62 | # icon: mdi:toggle-switch-variant 63 | filters: 64 | - delayed_on_off: 50ms 65 | on_press: 66 | then: 67 | - sensor.template.publish: 68 | id: clack_watermeter 69 | state: !lambda |- 70 | return id(totalWaterUsage) += 2; 71 | - sensor.template.publish: 72 | id: clack_m3_left 73 | state: !lambda |- 74 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 75 | - sensor.template.publish: 76 | id: clack_l_left 77 | state: !lambda |- 78 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 79 | 80 | ## regeneration pulse / relay 2 81 | - platform: gpio 82 | pin: 83 | number: 18 # lilygo ESP32S3 T7-S3: 18, mh-et-live: 18, wemos d1 mini -D5 84 | inverted: true 85 | mode: 86 | input: true 87 | pullup: true 88 | id: clack_regeneration_pulse 89 | name: ${clack_regeneration_pulse} 90 | # icon: mdi:toggle-switch-variant 91 | filters: 92 | - delayed_on_off: 800ms 93 | on_press: 94 | then: 95 | - globals.set: 96 | id: totalWaterUsage 97 | value: '00' 98 | - text_sensor.template.publish: 99 | id: clack_regeneration_last 100 | state: !lambda |- 101 | char str[22]; 102 | time_t currTime = id(clack_sntp_time).now().timestamp; 103 | strftime(str, sizeof(str), "%a %d %b %H:%M", localtime(&currTime)); 104 | return { str }; 105 | - sensor.template.publish: 106 | id: clack_watermeter 107 | state: !lambda |- 108 | return id(totalWaterUsage); 109 | - sensor.template.publish: 110 | id: clack_m3_left 111 | state: !lambda |- 112 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 113 | # return id(water_softener_m3_left).state; 114 | - sensor.template.publish: 115 | id: clack_l_left 116 | state: !lambda |- 117 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 118 | 119 | button: 120 | ## temporarely test button for testing reg puls 121 | - id: clack_use_test_button 122 | name: Test button use pulse 123 | platform: template 124 | on_press: 125 | then: 126 | - sensor.template.publish: 127 | id: clack_watermeter 128 | state: !lambda |- 129 | return id(totalWaterUsage) += 2; 130 | - sensor.template.publish: 131 | id: clack_m3_left 132 | state: !lambda |- 133 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 134 | - sensor.template.publish: 135 | id: clack_l_left 136 | state: !lambda |- 137 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 138 | - lambda: |- 139 | ESP_LOGI("UseTest", "button pressed"); 140 | 141 | ## temporarely test button for testing reg puls 142 | - id: clack_reg_test_button 143 | name: Test button reg pulse 144 | platform: template 145 | on_press: 146 | then: 147 | - globals.set: 148 | id: totalWaterUsage 149 | value: '00' 150 | - text_sensor.template.publish: 151 | id: clack_regeneration_last 152 | state: !lambda |- 153 | char str[32]; 154 | time_t currTime = id(clack_sntp_time).now().timestamp; 155 | strftime(str, sizeof(str), "%a %d %b %H:%M", localtime(&currTime)); 156 | return { str }; 157 | - sensor.template.publish: 158 | id: clack_watermeter 159 | state: !lambda |- 160 | return id(totalWaterUsage); 161 | - sensor.template.publish: 162 | id: clack_m3_left 163 | state: !lambda |- 164 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 165 | - sensor.template.publish: 166 | id: clack_l_left 167 | state: !lambda |- 168 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 169 | - lambda: |- 170 | ESP_LOGI("RegTest", "button pressed"); -------------------------------------------------------------------------------- /esphome/board-esp32-wemos-s3.yaml: -------------------------------------------------------------------------------- 1 | ### ESP32S3 used is a wemos s3 mini 2 | 3 | esp32: 4 | board: lolin_s3 5 | variant: esp32s3 6 | framework: 7 | type: arduino 8 | # version: latest 9 | # flash_size: 4MB 10 | 11 | # the DFrobot A02YYUW ultrasonic is uart 12 | uart: 13 | id: uart_bus 14 | tx_pin: 35 #SDA 15 | rx_pin: 36 #SCL 16 | baud_rate: 9600 17 | 18 | # get rid of CDC error 19 | esphome: 20 | platformio_options: 21 | # board_build.arduino.memory_type: qio_qspi 22 | # board_upload.ram_size: 327680 23 | # board_upload_maximum_size: 4193404 24 | # board_upload_speed: 460800 25 | # build_flags: [ 26 | # "-DBOARD_HAS_PSRAM", 27 | # "-DARDUINO_LOLIN_S3_MINI", 28 | # "-DARDUINO_USB_MODE=1"] 29 | board_build.extra_flags: 30 | - "-DARDUINO_USB_CDC_ON_BOOT=0" # Override, defaults to '-DARDUINO_USB_CDC_ON_BOOT=1' 31 | 32 | # Enable/Disable logging 33 | logger: 34 | logs: 35 | esp32.preferences: WARN 36 | sensor: WARN 37 | text_sensor: WARN 38 | switch: WARN 39 | button: WARN 40 | number: WARN 41 | # baud_rate: 0 # <--- super important! for ESP8266 42 | 43 | wifi: 44 | ap: 45 | ssid: "${name}" 46 | password: "configesp" 47 | 48 | # enable IMPROV wifi, connection hotspot via bluetooth. see https://www.improv-wifi.com/ 49 | #esp32_improv: 50 | # authorizer: None 51 | 52 | captive_portal: 53 | 54 | # Enable Web server. 55 | web_server: 56 | port: 80 57 | 58 | ## watermeter pulse / relay 1 59 | binary_sensor: 60 | - platform: gpio 61 | pin: 62 | number: 16 # wemos s3 mini: 16, lilygo ESP32S3 T7-S3: 12-1, mh-et-live: 16, wemos d1 mini -D4 63 | inverted: true 64 | mode: 65 | input: true 66 | pullup: true 67 | id: clack_watermeter_pulse 68 | name: ${clack_watermeter_pulse} 69 | # icon: mdi:toggle-switch-variant 70 | filters: 71 | - delayed_on_off: 50ms 72 | on_press: 73 | then: 74 | - sensor.template.publish: 75 | id: clack_watermeter 76 | state: !lambda |- 77 | return id(totalWaterUsage) += 2; 78 | - sensor.template.publish: 79 | id: clack_m3_left 80 | state: !lambda |- 81 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 82 | - sensor.template.publish: 83 | id: clack_l_left 84 | state: !lambda |- 85 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 86 | 87 | ## regeneration pulse / relay 2 88 | - platform: gpio 89 | pin: 90 | number: 12 # wemos s3 mini: 12, lilygo ESP32S3 T7-S3: 18, mh-et-live: 18, wemos d1 mini -D5 91 | inverted: true 92 | mode: 93 | input: true 94 | pullup: true 95 | id: clack_regeneration_pulse 96 | name: ${clack_regeneration_pulse} 97 | # icon: mdi:toggle-switch-variant 98 | filters: 99 | - delayed_on_off: 800ms 100 | on_press: 101 | then: 102 | - globals.set: 103 | id: totalWaterUsage 104 | value: '00' 105 | - text_sensor.template.publish: 106 | id: clack_regeneration_last 107 | state: !lambda |- 108 | char str[32]; 109 | time_t currTime = id(clack_sntp_time).now().timestamp; 110 | strftime(str, sizeof(str), "%a %d %b %H:%M", localtime(&currTime)); 111 | return { str }; 112 | - sensor.template.publish: 113 | id: clack_watermeter 114 | state: !lambda |- 115 | return id(totalWaterUsage); 116 | - sensor.template.publish: 117 | id: clack_m3_left 118 | state: !lambda |- 119 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 120 | - sensor.template.publish: 121 | id: clack_l_left 122 | state: !lambda |- 123 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 124 | 125 | button: 126 | ## temporary test button for testing water meter pulse 127 | - id: clack_use_test_button 128 | name: Test button use pulse 129 | platform: template 130 | on_press: 131 | then: 132 | - sensor.template.publish: 133 | id: clack_watermeter 134 | state: !lambda |- 135 | return id(totalWaterUsage) += 2; 136 | - sensor.template.publish: 137 | id: clack_m3_left 138 | state: !lambda |- 139 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 140 | - sensor.template.publish: 141 | id: clack_l_left 142 | state: !lambda |- 143 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 144 | - lambda: |- 145 | ESP_LOGI("UseTest", "Use button pressed"); 146 | 147 | ## temporary test button for testing regeneration pulse 148 | - id: clack_reg_test_button 149 | name: Test button regen pulse 150 | platform: template 151 | on_press: 152 | then: 153 | - globals.set: 154 | id: totalWaterUsage 155 | value: '00' 156 | - text_sensor.template.publish: 157 | id: clack_regeneration_last 158 | state: !lambda |- 159 | char str[32]; 160 | time_t currTime = id(clack_sntp_time).now().timestamp; 161 | strftime(str, sizeof(str), "%a %d %b %H:%M", localtime(&currTime)); 162 | return { str }; 163 | - sensor.template.publish: 164 | id: clack_watermeter 165 | state: !lambda |- 166 | return id(totalWaterUsage); 167 | - sensor.template.publish: 168 | id: clack_m3_left 169 | state: !lambda |- 170 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 171 | - sensor.template.publish: 172 | id: clack_l_left 173 | state: !lambda |- 174 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 175 | - lambda: |- 176 | ESP_LOGI("RegTest", "Regeneration button pressed"); 177 | -------------------------------------------------------------------------------- /home_assistant/clack_en.yaml: -------------------------------------------------------------------------------- 1 | #------------ 2 | #INPUT SELECT 3 | #------------ 4 | # Remark: The step second backwash, between Brine and Rinse is removed 5 | # Removing this step reduces the amount of wastewater en is probably not necessary for the performance of the softener 6 | # This can be setup in the clack menus. See manual. 7 | input_select: 8 | water_softener_status: 9 | name: Water softener status 10 | options: 11 | - Backwash 12 | - Brine 13 | - Rinse 14 | - Fill 15 | - Idle 16 | initial: Idle 17 | 18 | #----------- 19 | #TIMERS 20 | #----------- 21 | # Remark: change the timer settings, upon your own timing (measure time with stopwatch on the complet regen. cycle) 22 | timer: 23 | timer_ws_backwash: 24 | name: Backwash 25 | # duration: '0:00:57' 26 | duration: '0:00:10' 27 | 28 | timer_ws_brine: 29 | name: Brine 30 | # duration: '0:01:07' 31 | duration: '0:00:10' 32 | 33 | timer_ws_rinse: 34 | name: Rinse 35 | # duration: '0:01:14' 36 | duration: '0:00:10' 37 | 38 | timer_ws_fill: 39 | name: Fill 40 | # duration: '0:01:10' 41 | duration: '0:00:10' 42 | 43 | timer_ws_total: #sum of all above values 44 | name: Total 45 | # duration: '0:05:44' 46 | duration: '0:00:40' 47 | 48 | #----------- 49 | #SENSORS 50 | #----------- 51 | template: 52 | sensor: 53 | - name: "time_to_regeneration" # custom sensor that calculates the expected number of days till the next regeneration 54 | state: > 55 | {%- set time = (states('number.capacity_in_days') | int * 86400) - (as_timestamp(now()) - as_timestamp((strptime(states('sensor.water_softener_regenerated_on')[4:15], '%d %b %H:%M').replace(year=now().year)))) | int %} 56 | {%- set hours = ((time % 86400) // 3600) %} 57 | {%- set hours = '{}h '.format(hours) if hours > 0 else '' %} 58 | {%- set days = (time // 86400) %} 59 | {%- set days = '{}d '.format(days) if days > 0 else '' %} 60 | {{days + hours}} 61 | unique_id: "time_to_regeneration" 62 | icon: mdi:calendar-clock 63 | 64 | #----------- 65 | #UTILITY METER 66 | #----------- 67 | utility_meter: 68 | waterusage_this_quarter: 69 | source: sensor.water_meter 70 | cycle: quarter-hourly 71 | waterusage_this_hour: 72 | source: sensor.water_meter 73 | cycle: hourly 74 | waterusage_today: 75 | source: sensor.water_meter 76 | cycle: daily 77 | waterusage_this_month: 78 | source: sensor.water_meter 79 | cycle: monthly 80 | waterusage_this_year: 81 | source: sensor.water_meter 82 | cycle: yearly 83 | 84 | automation: 85 | #################################################### 86 | - id: set_water_softener_start_backwash 87 | alias: Set water softener start Backwash 88 | trigger: 89 | - platform: state 90 | entity_id: 91 | - binary_sensor.regeneration_pulse 92 | to: 'on' 93 | - platform: state 94 | entity_id: button.test_button_regen_pulse 95 | condition: 96 | - condition: and 97 | conditions: 98 | - condition: state 99 | entity_id: input_select.water_softener_status 100 | state: Idle 101 | action: 102 | - service: input_select.select_option 103 | data: 104 | entity_id: input_select.water_softener_status 105 | option: Backwash 106 | - service: timer.start 107 | entity_id: timer.timer_ws_backwash 108 | - service: timer.start 109 | entity_id: timer.timer_ws_total 110 | initial_state: true 111 | #################################################### 112 | - id: set_water_softener_start_brine 113 | alias: Set water softener start Brine 114 | trigger: 115 | - platform: event 116 | event_type: timer.finished 117 | event_data: 118 | entity_id: timer.timer_ws_backwash 119 | condition: 120 | - condition: and 121 | conditions: 122 | - condition: state 123 | entity_id: input_select.water_softener_status 124 | state: Backwash 125 | action: 126 | - service: input_select.select_option 127 | data: 128 | entity_id: input_select.water_softener_status 129 | option: Brine 130 | - service: timer.start 131 | entity_id: timer.timer_ws_brine 132 | initial_state: true 133 | #################################################### 134 | - id: set_water_softener_start_rinse 135 | alias: Set water softener start Rinse 136 | trigger: 137 | - platform: event 138 | event_type: timer.finished 139 | event_data: 140 | entity_id: timer.timer_ws_brine 141 | condition: 142 | - condition: and 143 | conditions: 144 | - condition: state 145 | entity_id: input_select.water_softener_status 146 | state: Brine 147 | action: 148 | - service: input_select.select_option 149 | data: 150 | entity_id: input_select.water_softener_status 151 | option: Rinse 152 | - service: timer.start 153 | entity_id: timer.timer_ws_rinse 154 | initial_state: true 155 | #################################################### 156 | - id: set_water_softener_start_fill 157 | alias: Set water softener start Fill 158 | trigger: 159 | - platform: event 160 | event_type: timer.finished 161 | event_data: 162 | entity_id: timer.timer_ws_rinse 163 | condition: 164 | - condition: and 165 | conditions: 166 | - condition: state 167 | entity_id: input_select.water_softener_status 168 | state: Rinse 169 | action: 170 | - service: input_select.select_option 171 | data: 172 | entity_id: input_select.water_softener_status 173 | option: Fill 174 | - service: timer.start 175 | entity_id: timer.timer_ws_fill 176 | initial_state: true 177 | #################################################### 178 | - id: set_water_softener_idle 179 | alias: Set water softener Idle 180 | trigger: 181 | - platform: event 182 | event_type: timer.finished 183 | event_data: 184 | entity_id: timer.timer_ws_fill 185 | condition: 186 | - condition: and 187 | conditions: 188 | - condition: state 189 | entity_id: input_select.water_softener_status 190 | state: Fill 191 | action: 192 | - service: input_select.select_option 193 | data: 194 | entity_id: input_select.water_softener_status 195 | option: Idle 196 | - service: esphome.clack_meterstand_clack 197 | data: 198 | meter_value: 0 199 | - service: input_number.set_value 200 | data_template: 201 | entity_id: input_number.water_softener_meter_liters 202 | value: 0 203 | initial_state: true 204 | #------------------------------------------------------------------ 205 | # Extra options: Salt level alarm and hardness measurement alarm. 206 | # Fill in your own mobile_app_iphone_van_xxx in. (as an example) 207 | #------------------------------------------------------------------ 208 | - id: salt_level_alarm_notify 209 | alias: Salt level alarm notify 210 | description: '' 211 | trigger: 212 | - platform: state 213 | entity_id: sensor.fill_salt 214 | to: "yes" 215 | condition: 216 | - condition: time 217 | after: 07:30:00 218 | before: '22:00:00' 219 | action: 220 | - service: notify.mobile_app_iphone_van_a_c_a 221 | data: 222 | title: Be aware! 223 | message: Salt level watersoftener is low! Fill salt today! 224 | data: 225 | push: 226 | sound: 227 | name: default 228 | critical: 1 229 | volume: 1 230 | - delay: 231 | minutes: 30 232 | initial_state: 'true' 233 | mode: single 234 | #################################################### 235 | - id: measure_hardness_notify 236 | alias: Measure Hardness 237 | description: '' 238 | trigger: 239 | - platform: numeric_state 240 | entity_id: 241 | - sensor.watermeter 242 | above: 3000 243 | condition: 244 | - condition: time 245 | after: 07:30:00 246 | before: '22:00:00' 247 | action: 248 | - service: notify.mobile_app_iphone_van_a_c_a 249 | data: 250 | title: Be aware! 251 | message: 'Measure hardness softener: used 3000 ltr' 252 | data: 253 | push: 254 | sound: 255 | name: default 256 | critical: 1 257 | volume: 1 258 | - delay: 259 | minutes: 30 260 | mode: single 261 | initial_state: 'true' 262 | -------------------------------------------------------------------------------- /home_assistant/clack_nl.yaml: -------------------------------------------------------------------------------- 1 | #------------ 2 | #INPUT SELECT 3 | #------------ 4 | # Opm: de stap 2e terugspoeling (backwash) is eruit gehaald, tussen zoutspoeling en snelspoeling. 5 | # Deze stap weghalen bespaart water en is mogelijk niet persee nodig. Dit kan ingesteld worden in de Clack 6 | input_select: 7 | water_softener_status: 8 | name: Water softener status 9 | options: 10 | - terugspoeling 11 | - zoutspoeling 12 | - snelspoeling 13 | - vullen 14 | - standby 15 | initial: standby 16 | 17 | #----------- 18 | #TIMERS 19 | #----------- 20 | # Opm: verander deze naar de eigen tijdsduur van de waterontharder (stopwatch) 21 | timer: 22 | timer_ws_backwash: 23 | name: terugspoeling 24 | # duration: '0:00:57' 25 | duration: '0:00:10' 26 | 27 | timer_ws_brine: 28 | name: zoutspoeling 29 | # duration: '0:01:07' 30 | duration: '0:00:10' 31 | 32 | timer_ws_rinse: 33 | name: snelspoeling 34 | # duration: '0:01:14' 35 | duration: '0:00:10' 36 | 37 | timer_ws_fill: 38 | name: vullen 39 | # duration: '0:01:10' 40 | duration: '0:00:10' 41 | 42 | timer_ws_total: #sum of all above values 43 | name: total 44 | # duration: '0:05:44' 45 | duration: '0:00:40' 46 | 47 | #----------- 48 | #SENSORS 49 | #----------- 50 | template: 51 | sensor: 52 | - name: "tijd_tot_regeneratie" # custom sensor die het aantal dagen berekend totdat opnieuw een regeneratie van de waterontharder moet plaatsvinden 53 | state: > 54 | {%- set time = (states('number.capaciteit_in_dagen') | int * 86400) - (as_timestamp(now()) - as_timestamp((strptime(states('sensor.waterontharder_geregenereerd_op')[4:15], '%d %b %H:%M').replace(year=now().year)))) | int %} 55 | {%- set hours = ((time % 86400) // 3600) %} 56 | {%- set hours = '{}h '.format(hours) if hours > 0 else '' %} 57 | {%- set days = (time // 86400) %} 58 | {%- set days = '{}d '.format(days) if days > 0 else '' %} 59 | {{days + hours}} 60 | unique_id: "tijd_tot_regeneratie" 61 | icon: mdi:calendar-clock 62 | 63 | #----------- 64 | #UTILITY METER 65 | #----------- 66 | utility_meter: 67 | waterverbruik_dit_kwartier: 68 | source: sensor.watermeter 69 | cycle: quarter-hourly 70 | waterverbruik_dit_uur: 71 | source: sensor.watermeter 72 | cycle: hourly 73 | waterverbruik_vandaag: 74 | source: sensor.watermeter 75 | cycle: daily 76 | waterverbruik_maand: 77 | source: sensor.watermeter 78 | cycle: monthly 79 | waterverbruik_jaar: 80 | source: sensor.watermeter 81 | cycle: yearly 82 | 83 | #----------- 84 | #AUTOMATIONS 85 | #----------- 86 | automation: 87 | #################################################### 88 | - id: set_water_softener_start_backwash 89 | alias: Set water softener start backwash 90 | trigger: 91 | - platform: state 92 | entity_id: 93 | - binary_sensor.regeneratie_pulse 94 | to: 'on' 95 | - platform: state 96 | entity_id: button.test_button_regen_pulse 97 | condition: 98 | - condition: and 99 | conditions: 100 | - condition: state 101 | entity_id: input_select.water_softener_status 102 | state: standby 103 | action: 104 | - service: input_select.select_option 105 | data: 106 | entity_id: input_select.water_softener_status 107 | option: terugspoeling 108 | - service: timer.start 109 | entity_id: timer.timer_ws_backwash 110 | - service: timer.start 111 | entity_id: timer.timer_ws_total 112 | initial_state: true 113 | #################################################### 114 | - id: set_water_softener_start_brine 115 | alias: Set water softener start brine 116 | trigger: 117 | - platform: event 118 | event_type: timer.finished 119 | event_data: 120 | entity_id: timer.timer_ws_backwash 121 | condition: 122 | - condition: and 123 | conditions: 124 | - condition: state 125 | entity_id: input_select.water_softener_status 126 | state: terugspoeling 127 | action: 128 | - service: input_select.select_option 129 | data: 130 | entity_id: input_select.water_softener_status 131 | option: zoutspoeling 132 | - service: timer.start 133 | entity_id: timer.timer_ws_brine 134 | initial_state: true 135 | #################################################### 136 | - id: set_water_softener_start_rinse 137 | alias: Set water softener start rinse 138 | trigger: 139 | - platform: event 140 | event_type: timer.finished 141 | event_data: 142 | entity_id: timer.timer_ws_brine 143 | condition: 144 | - condition: and 145 | conditions: 146 | - condition: state 147 | entity_id: input_select.water_softener_status 148 | state: zoutspoeling 149 | action: 150 | - service: input_select.select_option 151 | data: 152 | entity_id: input_select.water_softener_status 153 | option: snelspoeling 154 | - service: timer.start 155 | entity_id: timer.timer_ws_rinse 156 | initial_state: true 157 | #################################################### 158 | - id: set_water_softener_start_fill 159 | alias: Set water softener start fill 160 | trigger: 161 | - platform: event 162 | event_type: timer.finished 163 | event_data: 164 | entity_id: timer.timer_ws_rinse 165 | condition: 166 | - condition: and 167 | conditions: 168 | - condition: state 169 | entity_id: input_select.water_softener_status 170 | state: snelspoeling 171 | action: 172 | - service: input_select.select_option 173 | data: 174 | entity_id: input_select.water_softener_status 175 | option: vullen 176 | - service: timer.start 177 | entity_id: timer.timer_ws_fill 178 | initial_state: true 179 | #################################################### 180 | - id: set_water_softener_idle 181 | alias: Set water softener Idle 182 | trigger: 183 | - platform: event 184 | event_type: timer.finished 185 | event_data: 186 | entity_id: timer.timer_ws_fill 187 | condition: 188 | - condition: and 189 | conditions: 190 | - condition: state 191 | entity_id: input_select.water_softener_status 192 | state: vullen 193 | action: 194 | - service: input_select.select_option 195 | data: 196 | entity_id: input_select.water_softener_status 197 | option: standby 198 | - service: esphome.clack_meterstand_clack 199 | data: 200 | meter_value: 0 201 | - service: input_number.set_value 202 | data_template: 203 | entity_id: input_number.water_softener_meter_liters 204 | value: 0 205 | initial_state: true 206 | #------------------------------------------------------------------ 207 | # Automatisering opties: alarm zoutmelding en alarm hardheid meten. 208 | # vul je eigen mobile_app_iphone_van_xxx in. (als voorbeeld) 209 | #------------------------------------------------------------------ 210 | - id: salt_level_alarm_notify 211 | alias: Zoutniveau alarm melding 212 | description: '' 213 | trigger: 214 | - platform: state 215 | entity_id: sensor.zout_bijvullen 216 | to: ja 217 | condition: 218 | - condition: time 219 | after: 07:30:00 220 | before: '22:00:00' 221 | action: 222 | - service: notify.mobile_app_iphone_van_a_c_a 223 | data: 224 | title: Let op! 225 | message: Zout niveau van ontharder is laag! Vandaag gaan bijvullen! 226 | data: 227 | push: 228 | sound: 229 | name: default 230 | critical: 1 231 | volume: 1 232 | - delay: 233 | minutes: 30 234 | initial_state: 'true' 235 | mode: single 236 | ################################################## 237 | - id: measure_hardness_notify 238 | alias: Hardheid meten 239 | description: '' 240 | trigger: 241 | - platform: numeric_state 242 | entity_id: 243 | - sensor.watermeter 244 | above: 3000 245 | condition: 246 | - condition: time 247 | after: 07:30:00 248 | before: '22:00:00' 249 | action: 250 | - service: notify.mobile_app_iphone_van_a_c_a 251 | data: 252 | title: Let op! 253 | data: 254 | push: 255 | sound: 256 | name: default 257 | critical: 1 258 | volume: 1 259 | message: 'Ontharder hardheid meten: nu 3000 ltr' 260 | - delay: 261 | minutes: 30 262 | mode: single 263 | initial_state: 'true' -------------------------------------------------------------------------------- /home_assistant/lovelace_menu_nl.yaml: -------------------------------------------------------------------------------- 1 | views: 2 | - title: Ontharder 3 | path: ontharder 4 | badges: [] 5 | cards: 6 | - type: vertical-stack 7 | cards: 8 | - cards: 9 | - type: entities 10 | entities: 11 | - entity: sensor.watermeter 12 | type: custom:multiple-entity-row 13 | icon: mdi:cup-water 14 | name: Water ontharder 15 | secondary_info: 16 | entity: input_select.water_softener_status 17 | name: 'cyclus: ' 18 | state_header: verbr. 19 | entities: 20 | - entity: sensor.tijd_tot_regeneratie 21 | name: nog dag 22 | - entity: sensor.waterontharder_m3_over 23 | name: nog m3 24 | style: | 25 | ha-card { 26 | border-radius: 20px 27 | } 28 | .card-header { 29 | font-size: 18px; 30 | padding: 5px 25px; 31 | font-weight: bold; 32 | } 33 | title: Water ontharder 34 | - entities: 35 | - entity: sensor.waterontharder_ltr_over 36 | max: 3200 37 | min: 0 38 | name: Ltr gebruikt 39 | height: 8px 40 | decimal: false 41 | positions: 42 | icon: 'off' 43 | indicator: 'off' 44 | tap_action: info 45 | name: 'off' 46 | value: 'off' 47 | style: | 48 | ha-card { 49 | border-radius: 20px 50 | } 51 | .card-content { 52 | padding: 0px 10px 10px 10px; 53 | } 54 | type: custom:bar-card 55 | mode: vertical 56 | type: custom:stack-in-card 57 | - type: conditional 58 | conditions: 59 | - entity: timer.timer_ws_total 60 | state_not: idle 61 | card: 62 | type: entities 63 | style: | 64 | 65 | .card-content { 66 | padding: 8px; 67 | } 68 | .card-content > div { 69 | margin: 0 !important; 70 | } 71 | .card-header { 72 | font-size: 18px; 73 | padding: 5px 25px; 74 | font-weight: bold; 75 | } 76 | .card-header { 77 | font-size: 18px; 78 | padding: 5px 25px; 79 | font-weight: bold; 80 | } 81 | title: Regen. gestart 82 | entities: 83 | - conditions: 84 | - entity: timer.timer_ws_backwash 85 | state_not: idle 86 | row: 87 | entity: timer.timer_ws_backwash 88 | icon: mdi:numeric-1-circle 89 | name: 'Cyclus: terugspoelen' 90 | type: conditional 91 | - conditions: 92 | - entity: timer.timer_ws_brine 93 | state_not: idle 94 | row: 95 | entity: timer.timer_ws_brine 96 | icon: mdi:numeric-2-circle 97 | name: 'Cyclus: zoutspoeling' 98 | type: conditional 99 | - conditions: 100 | - entity: timer.timer_ws_rinse 101 | state_not: idle 102 | row: 103 | entity: timer.timer_ws_rinse 104 | icon: mdi:numeric-4-circle 105 | name: 'Cyclus: snelspoeling' 106 | type: conditional 107 | - conditions: 108 | - entity: timer.timer_ws_fill 109 | state_not: idle 110 | row: 111 | entity: timer.timer_ws_fill 112 | icon: mdi:numeric-5-circle 113 | name: 'Cyclus: vullen' 114 | type: conditional 115 | - type: section 116 | - entity: timer.timer_ws_total 117 | icon: mdi:timer-sand 118 | name: Totale tijd over (4 cycles) 119 | - type: entities 120 | entities: 121 | - entity: sensor.watermeter 122 | - entity: sensor.waterontharder_ltr_over 123 | name: Waterontharder ltr over 124 | - entity: sensor.waterontharder_m3_over 125 | name: Waterontharder m3 over 126 | - entity: sensor.zoutniveau_afstand 127 | name: Afstand 128 | - entity: sensor.zoutniveau_hoogte 129 | name: Hoogte 130 | - entity: sensor.zoutniveau_procent 131 | name: Procent 132 | - entity: sensor.zout_bijvullen 133 | - entity: sensor.waterontharder_geregenereerd_op 134 | - entity: binary_sensor.watermeter_pulse 135 | - entity: binary_sensor.regeneratie_pulse 136 | - entity: sensor.salt_level 137 | - entity: button.test_button_use_pulse 138 | - entity: button.test_button_regen_pulse 139 | - entity: switch.fancoil 140 | name: Power 141 | - elements: 142 | - entity: sensor.salt_level 143 | image: local/images/softener.png 144 | state_image: 145 | '0': local/images/softener0.png 146 | '10': local/images/softener10.png 147 | '20': local/images/softener20.png 148 | '40': local/images/softener40.png 149 | '60': local/images/softener60.png 150 | '80': local/images/softener80.png 151 | '100': local/images/softener100.png 152 | style: 153 | left: 0% 154 | top: 0% 155 | transform: scale(1,1) 156 | tap_action: 157 | action: none 158 | type: image 159 | image: local/images/softener.png 160 | panel: true 161 | type: picture-elements 162 | - type: entities 163 | entities: 164 | - entity: sensor.waterverbruik_dit_kwartier 165 | - entity: sensor.waterverbruik_dit_uur 166 | - entity: sensor.waterverbruik_vandaag 167 | - entity: sensor.waterverbruik_maand 168 | - entity: sensor.waterverbruik_jaar 169 | - type: custom:apexcharts-card 170 | graph_span: 7d 171 | update_interval: 5m 172 | cache: true 173 | span: 174 | end: day 175 | offset: '-1sec' 176 | header: 177 | show: true 178 | title: Water per dag 179 | apex_config: 180 | xaxis: 181 | labels: 182 | format: dd-MM 183 | show: true 184 | showAlways: true 185 | yaxis: 186 | forceNiceScale: true 187 | decimalsInFloat: 0 188 | min: 0 189 | chart: 190 | type: area 191 | height: 300 192 | stroke: 193 | show: true 194 | width: 1 195 | legend: 196 | show: true 197 | dataLabels: 198 | enabled: false 199 | distributed: true 200 | fill: 201 | type: gradient 202 | gradient: 203 | shadeIntensity: 0.1 204 | opacityFrom: 0.25 205 | opacityTo: 1 206 | inverseColors: true 207 | stops: 208 | - 0 209 | - 90 210 | - 100 211 | series: 212 | - entity: sensor.waterverbruik_vandaag 213 | name: Verbruik 214 | type: column 215 | float_precision: 2 216 | group_by: 217 | func: max 218 | duration: 23h59m59s 219 | - type: entities 220 | entities: 221 | - entity: number.min_afstand_zout 222 | - entity: number.max_afstand_zout 223 | - entity: number.zout_bijvullen_afstand 224 | - entity: number.capaciteit_in_dagen 225 | - entity: number.capaciteit_in_liters 226 | - entity: sensor.versie 227 | - entity: sensor.waterontharder_ip 228 | - entity: sensor.wifi_signal 229 | - entity: sensor.wifi_signal_db 230 | title: Instellingen -------------------------------------------------------------------------------- /home_assistant/lovelace_menu_en.yaml: -------------------------------------------------------------------------------- 1 | views: 2 | - title: Watersoftener 3 | path: watersoftener 4 | badges: [] 5 | cards: 6 | - type: vertical-stack 7 | cards: 8 | - cards: 9 | - type: entities 10 | entities: 11 | - entity: sensor.water_meter 12 | type: custom:multiple-entity-row 13 | icon: mdi:cup-water 14 | name: Water softener 15 | secondary_info: 16 | entity: input_select.water_softener_status 17 | name: 'cycle: ' 18 | state_header: used 19 | entities: 20 | - entity: sensor.time_to_regeneration 21 | name: time left 22 | - entity: sensor.water_softener_m3_left 23 | name: m3 left 24 | style: | 25 | ha-card { 26 | border-radius: 20px 27 | } 28 | .card-header { 29 | font-size: 18px; 30 | padding: 5px 25px; 31 | font-weight: bold; 32 | } 33 | title: Water softener 34 | - entities: 35 | - entity: sensor.water_softener_ltr_left 36 | max: 3200 37 | min: 0 38 | name: L used 39 | height: 8px 40 | decimal: false 41 | positions: 42 | icon: 'off' 43 | indicator: 'off' 44 | tap_action: info 45 | name: 'off' 46 | value: 'off' 47 | style: | 48 | ha-card { 49 | border-radius: 20px 50 | } 51 | .card-content { 52 | padding: 0px 10px 10px 10px; 53 | } 54 | type: custom:bar-card 55 | mode: vertical 56 | type: custom:stack-in-card 57 | - type: conditional 58 | conditions: 59 | - entity: timer.timer_ws_total 60 | state_not: idle 61 | card: 62 | type: entities 63 | style: | 64 | 65 | .card-content { 66 | padding: 8px; 67 | } 68 | .card-content > div { 69 | margin: 0 !important; 70 | } 71 | .card-header { 72 | font-size: 18px; 73 | padding: 5px 25px; 74 | font-weight: bold; 75 | } 76 | .card-header { 77 | font-size: 18px; 78 | padding: 5px 25px; 79 | font-weight: bold; 80 | } 81 | title: Regen. started 82 | entities: 83 | - conditions: 84 | - entity: timer.timer_ws_backwash 85 | state_not: idle 86 | row: 87 | entity: timer.timer_ws_backwash 88 | icon: mdi:numeric-1-circle 89 | name: 'Cycle: Backwash' 90 | type: conditional 91 | - conditions: 92 | - entity: timer.timer_ws_brine 93 | state_not: idle 94 | row: 95 | entity: timer.timer_ws_brine 96 | icon: mdi:numeric-2-circle 97 | name: 'Cycle: Brine' 98 | type: conditional 99 | - conditions: 100 | - entity: timer.timer_ws_rinse 101 | state_not: idle 102 | row: 103 | entity: timer.timer_ws_rinse 104 | icon: mdi:numeric-3-circle 105 | name: 'Cycle: Rinse' 106 | type: conditional 107 | - conditions: 108 | - entity: timer.timer_ws_fill 109 | state_not: idle 110 | row: 111 | entity: timer.timer_ws_fill 112 | icon: mdi:numeric-4-circle 113 | name: 'Cycle: Fill' 114 | type: conditional 115 | - type: section 116 | - entity: timer.timer_ws_total 117 | icon: mdi:timer-sand 118 | name: Total time left (4 cycles) 119 | - type: entities 120 | entities: 121 | - entity: sensor.water_meter 122 | - entity: sensor.water_softener_ltr_left 123 | - entity: sensor.water_softener_m3_left 124 | - entity: sensor.salt_level_distance 125 | name: Distance 126 | - entity: sensor.salt_level_height 127 | name: Height 128 | - entity: sensor.salt_level_percent 129 | name: Procent 130 | - entity: sensor.fill_salt 131 | - entity: sensor.water_softener_regenerated_on 132 | - entity: binary_sensor.watermeter_pulse 133 | - entity: binary_sensor.regeneration_pulse 134 | - entity: sensor.salt_level 135 | - entity: button.test_button_use_pulse 136 | - entity: button.test_button_regen_pulse 137 | - elements: 138 | - entity: sensor.salt_level 139 | image: local/images/softener.png 140 | state_image: 141 | '0': local/images/softener0.png 142 | '10': local/images/softener10.png 143 | '20': local/images/softener20.png 144 | '40': local/images/softener40.png 145 | '60': local/images/softener60.png 146 | '80': local/images/softener80.png 147 | '100': local/images/softener100.png 148 | style: 149 | left: 0% 150 | top: 0% 151 | transform: scale(1,1) 152 | tap_action: 153 | action: none 154 | type: image 155 | image: local/images/softener.png 156 | panel: true 157 | type: picture-elements 158 | - type: entities 159 | entities: 160 | - entity: sensor.waterusage_this_quarter 161 | name: Waterusage last quarter 162 | - entity: sensor.waterusage_this_hour 163 | name: Waterusage last hour 164 | - entity: sensor.waterusage_today 165 | name: Waterusage today 166 | - entity: sensor.waterusage_this_month 167 | name: Waterusage this month 168 | - entity: sensor.waterusage_this_year 169 | name: Waterusage this year 170 | - type: custom:apexcharts-card 171 | graph_span: 7d 172 | update_interval: 5m 173 | cache: true 174 | span: 175 | end: day 176 | offset: '-1sec' 177 | header: 178 | show: true 179 | title: Water per day 180 | apex_config: 181 | xaxis: 182 | labels: 183 | format: dd-MM 184 | show: true 185 | showAlways: true 186 | yaxis: 187 | forceNiceScale: true 188 | decimalsInFloat: 0 189 | min: 0 190 | chart: 191 | type: area 192 | height: 300 193 | stroke: 194 | show: true 195 | width: 1 196 | legend: 197 | show: true 198 | dataLabels: 199 | enabled: false 200 | distributed: true 201 | fill: 202 | type: gradient 203 | gradient: 204 | shadeIntensity: 0.1 205 | opacityFrom: 0.25 206 | opacityTo: 1 207 | inverseColors: true 208 | stops: 209 | - 0 210 | - 90 211 | - 100 212 | series: 213 | - entity: sensor.waterusage_today 214 | name: Usage 215 | type: column 216 | float_precision: 2 217 | group_by: 218 | func: max 219 | duration: 23h59m59s 220 | - type: entities 221 | entities: 222 | - entity: number.min_salt_distance 223 | - entity: number.max_salt_distance 224 | - entity: number.fill_salt_distance 225 | - entity: number.capacity_in_days 226 | - entity: number.capacity_in_liters 227 | - entity: sensor.versie 228 | - entity: sensor.waterontharder_ip 229 | - entity: sensor.wifi_signal 230 | - entity: sensor.wifi_signal_db 231 | title: Settings -------------------------------------------------------------------------------- /esphome/clack.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | name: clack 3 | device_description: "Esphome component for Clack WS1 softener with ultrasonic sensor saltlevel detection" 4 | timezone: "Europe/Amsterdam" 5 | 6 | # In order to use other language or a different ESP chip, fix include file name below: 7 | # Currently supported languages are en, nl. 8 | # ESP32 is a mh-et-live or wemos d32 mini, esp8266 is a wemos d1 mini, esp32s3 is a lilygo ESP32S3-T7, 9 | # ESP32-wemos-s3 is a wemos S3 mini 10 | 11 | packages: 12 | remote_package: 13 | url: https://github.com/fonske/clack-reader 14 | ref: main 15 | refresh: 0s 16 | files: [ esphome/.clack-labels-en.yaml, esphome/board-esp32-wemos-s3.yaml ] 17 | ## choices are: esphome/.clack-labels-en.yaml, esphome/.clack-labels-nl.yaml 18 | ## esphome/board-esp32.yaml, esphome/board-esp32s3.yaml, 19 | ## esphome/board-esp32-wemos-s3.yaml, esphome/board-esp8266.yaml 20 | 21 | ## for developing/testing, uncomment local includes and comment out above remote_package packages part. 22 | #packages: 23 | # substitutions: !include .clack-labels-en.yaml 24 | # substitutions: !include .clack-labels-nl.yaml 25 | # device_base1: !include board-esp32.yaml 26 | # device_base1: !include board-esp32s3.yaml 27 | # device_base1: !include board-esp32-wemos-s3.yaml 28 | # device_base1: !include board-esp8266.yaml 29 | 30 | esphome: 31 | name: ${name} 32 | includes: 33 | - distance-sensor2.h 34 | on_boot: 35 | priority: 200 36 | then: 37 | - script.execute: on_boot 38 | 39 | # Enable Home Assistant API 40 | api: 41 | reboot_timeout: 0s 42 | services: 43 | - service: meterstand_clack 44 | variables: 45 | meter_value: float 46 | then: 47 | - globals.set: 48 | id: totalWaterUsage 49 | value: !lambda "return ( meter_value ) ;" 50 | 51 | time: 52 | - platform: sntp 53 | id: clack_sntp_time 54 | timezone: ${timezone} 55 | 56 | #update for esphome 2024.6.0 57 | # OTA: 58 | ota: 59 | platform: esphome 60 | 61 | wifi: 62 | ssid: !secret wifi_ssid 63 | password: !secret wifi_password 64 | fast_connect: true 65 | 66 | # Enable fallback hotspot (captive portal) in case wifi connection fails 67 | ap: 68 | ssid: "${name}" 69 | password: "configesp" 70 | ap_timeout: 15s 71 | 72 | script: 73 | ### On reboot or powerloss of the esp, set the time left counter 74 | - id: on_boot 75 | then: 76 | - text_sensor.template.publish: 77 | id: clack_regeneration_last 78 | state: !lambda |- 79 | char str[32]; 80 | time_t currTime = id(clack_sntp_time).now().timestamp; 81 | strftime(str, sizeof(str), "%a %d %b %H:%M", localtime(&currTime)); 82 | return { str }; 83 | 84 | globals: 85 | - id: totalWaterUsage 86 | type: float 87 | restore_value: yes 88 | initial_value: '00' 89 | 90 | #----------- 91 | #SENSORS 92 | #----------- 93 | sensor: 94 | # ultrasonic distance sensor. 95 | - platform: custom 96 | lambda: |- 97 | auto height_sensor = new DistanceSensor(150, id(uart_bus)); 98 | App.register_component(height_sensor); 99 | return {height_sensor}; 100 | sensors: 101 | name: ${clack_distance} 102 | id: clack_distance 103 | unit_of_measurement: cm 104 | accuracy_decimals: 1 105 | icon: "mdi:arrow-expand-vertical" 106 | filters: 107 | - throttle: 5s 108 | - filter_out: nan 109 | - delta: 0.5 110 | on_value: 111 | then: 112 | - sensor.template.publish: 113 | id: clack_procent 114 | state: !lambda |- 115 | const float max_distance = id(clack_saltlevel_height_max).state; // heigt in cm to lowest level 116 | const float min_distance = id(clack_saltlevel_height_min).state; // height in cm to highest level 117 | return int((1-((id(clack_distance).state - min_distance)/max_distance))*100); 118 | - sensor.template.publish: 119 | id: clack_height 120 | state: !lambda |- 121 | const float max_distance = id(clack_saltlevel_height_max).state; // height in cm to lowest level 122 | return max_distance-id(clack_distance).state; 123 | - text_sensor.template.publish: 124 | id: clack_fill_salt 125 | state: !lambda |- 126 | if (id(clack_height).state < id(clack_saltlevel_height_fill).state) { 127 | return {"${clack_yes}"}; 128 | } else { 129 | return {"${clack_no}"}; 130 | } 131 | 132 | 133 | # ultrasonic distance sensor calculate tank_percentage 134 | - platform: template 135 | id: clack_procent 136 | name: ${clack_procent} 137 | unit_of_measurement: "%" 138 | accuracy_decimals: 0 139 | icon: "mdi:percent-box-outline" 140 | update_interval: 600s 141 | filters: 142 | - lambda: |- 143 | if (x >= 100) return 100.0; 144 | else if (x <= 0.0) return 0.0; 145 | else return x; 146 | 147 | # Saltlevel animation picture on dashboard 148 | - platform: copy 149 | source_id: clack_procent 150 | id: clack_salt_level 151 | name: Salt level 152 | filters: 153 | - lambda: |- 154 | if (x >= 80) return 100; 155 | else if (x >= 65 && x <= 79) return 80; 156 | else if (x >= 40 && x <= 64) return 60; 157 | else if (x >= 20 && x <= 39) return 40; 158 | else if (x >= 10 && x <= 19) return 20; 159 | else if (x >= 5 && x <= 9) return 10; 160 | else if (x <= 4) return 0; 161 | else return x; 162 | 163 | 164 | # ultrasonic distance sensor calculate salt level from bottom 165 | - platform: template 166 | id: clack_height 167 | name: ${clack_height} 168 | unit_of_measurement: cm 169 | accuracy_decimals: 1 170 | icon: "mdi:hydraulic-oil-level" 171 | update_interval: 600s 172 | filters: 173 | - lambda: |- 174 | if (x >= 100) return 100.0; 175 | else if (x <= 0.0) return 0.0; 176 | else return x; 177 | 178 | 179 | ##################################################################### 180 | # CLACK 181 | ##################################################################### 182 | 183 | # Watermeter 184 | - platform: template 185 | id: clack_watermeter 186 | name: ${clack_watermeter_total} 187 | icon: mdi:water 188 | update_interval: 600s 189 | unit_of_measurement: L 190 | device_class: water 191 | state_class: total_increasing 192 | accuracy_decimals: 0 193 | lambda: |- 194 | return id(totalWaterUsage); 195 | 196 | - platform: template 197 | id: clack_m3_left 198 | name: ${clack_m3_left} 199 | unit_of_measurement: m³ 200 | device_class: water 201 | accuracy_decimals: 2 202 | update_interval: 600s 203 | 204 | - platform: template 205 | id: clack_l_left 206 | name: ${clack_l_left} 207 | unit_of_measurement: L 208 | device_class: water 209 | accuracy_decimals: 0 210 | update_interval: 600s 211 | 212 | # Diagnostics wifi and uptime 213 | - platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB 214 | id: clack_wifi_signal_db 215 | name: WiFi Signal dB 216 | update_interval: 60s 217 | entity_category: diagnostic 218 | 219 | - platform: copy # Reports the WiFi signal strength in % 220 | source_id: clack_wifi_signal_db 221 | id: clack_wifi_signal_db_percent 222 | name: WiFi Signal 223 | filters: 224 | - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0); 225 | unit_of_measurement: "%" 226 | entity_category: diagnostic 227 | 228 | - platform: uptime 229 | id: clack_uptime 230 | name: ${clack_uptime} 231 | unit_of_measurement: ${days} 232 | update_interval: 3600s 233 | accuracy_decimals: 1 234 | filters: 235 | - multiply: 0.000011574 236 | 237 | # Text sensors with general information. 238 | text_sensor: 239 | # Expose ESPHome version as sensor. 240 | - platform: version 241 | id: clack_version 242 | name: ${clack_version} 243 | hide_timestamp: true 244 | 245 | # Expose WiFi information as sensors. 246 | - platform: wifi_info 247 | ip_address: 248 | name: ${clack_ip} 249 | icon: mdi:ip-network 250 | 251 | # Textsensor "Fill Salt" yes or no. 252 | - platform: template 253 | name: ${clack_fill_salt} 254 | id: clack_fill_salt 255 | icon: mdi:basket-fill 256 | update_interval: never 257 | 258 | # imput numbers as boxes for setting the dimensions of the tank and level alarm. 259 | number: 260 | ## Set minimum distance (from bottom sensor / underneath plastic cap) 261 | - platform: template 262 | id: clack_saltlevel_height_min 263 | name: ${clack_saltlevel_height_min} 264 | icon: mdi:toggle-switch-variant 265 | optimistic: true 266 | mode: slider 267 | step: 0.5 268 | entity_category: config 269 | min_value: 0 270 | max_value: 10 271 | initial_value: 0 272 | restore_value: yes 273 | unit_of_measurement: cm 274 | on_value: 275 | then: 276 | - sensor.template.publish: 277 | id: clack_procent 278 | state: !lambda |- 279 | const float max_distance = id(clack_saltlevel_height_max).state; // heigt in cm to lowest level 280 | const float min_distance = id(clack_saltlevel_height_min).state; // height in cm to highest level 281 | return int((1-((id(clack_distance).state - min_distance)/max_distance))*100); 282 | - sensor.template.publish: 283 | id: clack_height 284 | state: !lambda |- 285 | const float max_distance = id(clack_saltlevel_height_max).state; // height in cm to lowest level 286 | return max_distance-id(clack_distance).state; 287 | 288 | ## Set maximum distance (from bottom sensor / underneath plastic cap) to water level (to measure in pipe?) 289 | - platform: template 290 | id: clack_saltlevel_height_max 291 | name: ${clack_saltlevel_height_max} 292 | icon: mdi:toggle-switch-variant-off 293 | optimistic: true 294 | mode: slider 295 | step: 0.5 296 | entity_category: config 297 | min_value: 0 298 | max_value: 100 299 | initial_value: 30 300 | restore_value: yes 301 | unit_of_measurement: cm 302 | on_value: 303 | then: 304 | - sensor.template.publish: 305 | id: clack_procent 306 | state: !lambda |- 307 | const float max_distance = id(clack_saltlevel_height_max).state; // heigt in cm to lowest level 308 | const float min_distance = id(clack_saltlevel_height_min).state; // height in cm to highest level 309 | return int((1-((id(clack_distance).state - min_distance)/max_distance))*100); 310 | - sensor.template.publish: 311 | id: clack_height 312 | state: !lambda |- 313 | const float max_distance = id(clack_saltlevel_height_max).state; // height in cm to lowest level 314 | return max_distance-id(clack_distance).state; 315 | 316 | ## Set alarm level 317 | - platform: template 318 | id: clack_saltlevel_height_fill 319 | name: ${clack_saltlevel_height_fill} 320 | icon: mdi:hydraulic-oil-temperature 321 | optimistic: true 322 | mode: slider 323 | step: 0.1 324 | entity_category: config 325 | min_value: 0 326 | max_value: 10 327 | initial_value: 1.5 328 | restore_value: yes 329 | unit_of_measurement: cm 330 | update_interval: 600s 331 | on_value: 332 | then: 333 | - text_sensor.template.publish: 334 | id: clack_fill_salt 335 | state: !lambda |- 336 | if (id(clack_height).state < id(clack_saltlevel_height_fill).state) { 337 | return {"${clack_yes}"}; 338 | } else { 339 | return {"${clack_no}"}; 340 | } 341 | 342 | ## Set capacity liters 343 | - platform: template 344 | id: clack_capacity_liters 345 | name: ${clack_capacity_liters} 346 | icon: mdi:water-opacity 347 | optimistic: true 348 | mode: slider 349 | step: 50 350 | entity_category: config 351 | min_value: 0 352 | max_value: 7200 353 | initial_value: 3200 354 | restore_value: yes 355 | unit_of_measurement: L 356 | on_value: 357 | then: 358 | - sensor.template.publish: 359 | id: clack_watermeter 360 | state: !lambda |- 361 | return id(totalWaterUsage); 362 | - sensor.template.publish: 363 | id: clack_m3_left 364 | state: !lambda |- 365 | return float(id(clack_capacity_liters).state - id(clack_watermeter).state) * 0.001; 366 | - sensor.template.publish: 367 | id: clack_l_left 368 | state: !lambda |- 369 | return int(id(clack_capacity_liters).state - id(clack_watermeter).state); 370 | 371 | ## Set capacity days 372 | - platform: template 373 | id: clack_capacity_days 374 | name: ${clack_capacity_days} 375 | icon: mdi:calendar-clock 376 | optimistic: true 377 | mode: slider 378 | step: 1 379 | entity_category: config 380 | min_value: 0 381 | max_value: 21 382 | initial_value: 10 383 | restore_value: yes 384 | unit_of_measurement: "${days}" 385 | --------------------------------------------------------------------------------