I have long thought about automating the input of hot and cold water. And not so long ago a flask of a cold water filter burst, flooding my house by 12 centimeters. Everything at home swam
I ordered electro-water valves on Aliexpress, a board with four relays and an ESP8285 + RF, 4 leakage sensors. This is not advertising, I just write where I bought it.
Board - https://www.aliexpress.com/item/33047968234.html
Water leak sensor - https://www.aliexpress.com/item/32961220211.html
Motorized Valves - https://www.aliexpress.com/item/32960239345.html
I ordered 2 valves with manual override (CR301 + TF15-B2-B + BSP + DC12V) but got one what I ordered and second ( CR301 + TF15-B2-A + BSP + DC12V) with out manual override. Seller sent new valve with manual override! Highly recommend seller!
First I flashed 4CH Relay board with Tasmota, I have noticed that when you reset, 3 relays are activated briefly, I re-flashed on ESPHome, nothing has changed. So i decided to build custom hardware.
I used ESP32 module + RF module
Since the valve is controlled via the + 12V line, the control is assembled on two MOSFETs. N-MOSFET + P-MOSFET
I used the N-channel MOSFET IRLML6244TRPBF and the P-channel MOSFET IRLML2244TRPBF
ESPHome full config:
esphome:
name: valvectrl
platform: ESP32
board: esp32dev
wifi:
ssid: "ITTC2-WiFi"
password: !secret
domain: .mydomain.com.ua
fast_connect: true
manual_ip:
static_ip: 192.168.1.1
gateway: 192.168.1.254
subnet: 255.255.255.0
dns1: 192.168.1.250
dns2: 192.168.1.251
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "valvectrl"
password: !secret
time:
- platform: sntp
id: sntp_time
servers: ntp.mydomain.com.ua
timezone: Europe/Kiev
# web_server:
# port: 80
# captive_portal:
# Enable logging
logger:
level: INFO
# Enable Home Assistant API
api:
password: !secret
reboot_timeout: 30min
ota:
password: !secret
# esp32_ble_tracker:
# scan_interval: 30s
globals:
- id: var_cold_open
type: bool
restore_value: yes
# initial_value: 'true'
- id: var_hot_open
type: bool
restore_value: yes
# initial_value: 'false'
- id: var_run_script
type: bool
initial_value: 'false'
- id: var_water_leak
type: bool
restore_value: yes
initial_value: 'false'
dallas:
- pin: GPIO23
update_interval: 30s
sensor:
- platform: dallas
address: 0xD00000067FEC5B28
id: temp1
name: "Temp Cold Water"
accuracy_decimals: 1
filters:
- sliding_window_moving_average:
window_size: 3
send_every: 3
- or:
- delta: 0.5
on_value:
then:
- lambda: |-
ESP_LOGD("main", "Value of temp1 %f", id(temp1).state);
id(temp1).publish_state(x);
- platform: dallas
address: 0x4F00000680EC9E28
id: temp2
name: "Temp Hot Water"
accuracy_decimals: 1
filters:
# - offset: 2.0
- sliding_window_moving_average:
window_size: 3
send_every: 3
- or:
- delta: 0.5
on_value:
then:
- lambda: |-
ESP_LOGD("main", "Value of temp2 %f", id(temp2).state);
id(temp2).publish_state(x);
- platform: wifi_signal
name: "WiFi Signal Sensor"
id: wifi_signal_sensor
update_interval: 30s
filters:
- median:
window_size: 5
send_every: 5
send_first_at: 1
on_value:
then:
- lambda: |-
id(wifi_signal_sensor).publish_state(x);
- platform: uptime
name: Uptime Sensor
remote_receiver:
pin: GPIO27
dump:
- rc_switch
# Settings to optimize recognition of RF devices
tolerance: 50%
filter: 250us
idle: 4ms
buffer_size: 2kb
## 1
# Received RCSwitch Raw: protocol=1 data='100111111111010110011110'
# Received RCSwitch Raw: protocol=1 data='100111111111010110010101' Button Battery Test
## 2
# Received RCSwitch Raw: protocol=1 data='101011000111000010001110'
# Received RCSwitch Raw: protocol=1 data='101011000111000010000101' Button Battery Test
## 3
# Received RCSwitch Raw: protocol=1 data='100010101001110110111110'
# Received RCSwitch Raw: protocol=1 data='100010101001110110110101' Button Battery Test
## 4
# Received RCSwitch Raw: protocol=1 data='100110000111000010001110'
# Received RCSwitch Raw: protocol=1 data='100110000111000010000101' Button Battery Test
binary_sensor:
- platform: remote_receiver
# name: "Water Leak 1"
id: water_leak_1
rc_switch_raw:
code: "100111111111010110011110"
protocol: 1
on_press:
then:
- script.execute: scr_wvalves_close
- binary_sensor.template.publish:
id: bin_wsensor_1
state: ON
- platform: remote_receiver
# name: "Water Leak 2"
id: water_leak_2
rc_switch_raw:
code: "101011000111000010001110"
protocol: 1
on_press:
then:
- script.execute: scr_wvalves_close
- binary_sensor.template.publish:
id: bin_wsensor_2
state: ON
- platform: remote_receiver
# name: "Water Leak 3"
id: water_leak_3
rc_switch_raw:
code: "100010101001110110111110"
protocol: 1
on_press:
then:
- script.execute: scr_wvalves_close
- binary_sensor.template.publish:
id: bin_wsensor_3
state: ON
- platform: remote_receiver
# name: "Water Leak 4"
id: water_leak_4
rc_switch_raw:
code: "100110000111000010001110"
protocol: 1
on_press:
then:
- script.execute: scr_wvalves_close
- binary_sensor.template.publish:
id: bin_wsensor_4
state: ON
- platform: remote_receiver
# name: "Water Leak 1 Button"
id: water_leak_1_button
rc_switch_raw:
code: "100111111111010110010101"
protocol: 1
on_press:
then:
- script.execute: scr_wvalves_close
- binary_sensor.template.publish:
id: bin_wsensor_1
state: ON
- platform: remote_receiver
# name: "Water Leak 2 Button"
id: water_leak_2_button
rc_switch_raw:
code: "101011000111000010000101"
protocol: 1
on_press:
then:
- script.execute: scr_wvalves_close
- binary_sensor.template.publish:
id: bin_wsensor_2
state: ON
# Show triggered sensors
- platform: template
device_class: moisture
id: 'bin_wsensor_1'
name: 'WSens1'
- platform: template
device_class: moisture
id: 'bin_wsensor_2'
name: 'WSens2'
- platform: template
device_class: moisture
id: 'bin_wsensor_3'
name: 'WSens3'
- platform: template
device_class: moisture
id: 'bin_wsensor_4'
name: 'WSens4'
- platform: template
device_class: opening
name: 'Cold Valve State'
id: 'cold_valve_state'
lambda: |-
if (id(var_cold_open) == true) {
return true;
} else {
return false;
}
# Valve states
- platform: template
device_class: opening
name: 'Hot Valve State'
id: 'Hot_valve_state'
lambda: |-
if (id(var_hot_open) == true) {
return true;
} else {
return false;
}
- platform: template
device_class: safety
name: 'Water leak'
id: 'water_leak_alert'
lambda: |-
if(id(var_water_leak) == true) {
return true;
} else {
return false;
}
script:
- id: scr_wvalves_close
then:
- lambda: !lambda |-
ESP_LOGD("RF-OnPress", "Alert triggered!!! Close Valves!!! Block Open!!!");
if (id(cov_cold_water).current_operation != COVER_OPERATION_CLOSING) {
id(cov_cold_water).close();
} else {
ESP_LOGD("RF-OnPress", "Already closing, nothing to do!");
}
if (id(cov_hot_water).current_operation != COVER_OPERATION_CLOSING) {
id(cov_hot_water).close();
} else {
ESP_LOGD("RF-OnPress", "Already closing, nothing to do!");
}
id(water_leak_alert).publish_state(true);
id(var_water_leak) = true;
# Switches
switch:
- platform: gpio
pin: 19
interlock: &interlock1 [cold_open, cold_close]
# name: "Cold open"
id: 'cold_open'
restore_mode: ALWAYS_OFF
- platform: gpio
pin: 21
interlock: *interlock1
# name: "Cold close"
id: 'cold_close'
restore_mode: ALWAYS_OFF
- platform: gpio
pin: 25
interlock: &interlock2 [hot_open, hot_close]
# name: "Hot open"
id: 'hot_open'
restore_mode: ALWAYS_OFF
- platform: gpio
pin: 32
interlock: *interlock2
# name: "Hot close"
id: 'hot_close'
restore_mode: ALWAYS_OFF
# Electric door lock
- platform: gpio
pin: 18
#name: "Door Lock"
id: 'door_lock'
restore_mode: ALWAYS_OFF
- platform: template
name: "Door Remote"
icon: "mdi:door"
turn_on_action:
- switch.turn_on: door_lock
- delay: 50ms
- switch.turn_off: door_lock
# Reset water leak alert
- platform: template
name: "Reset Water leak alert"
id: "reset_water_leak"
turn_on_action:
- lambda: !lambda |-
id(var_water_leak) = false;
id(water_leak_alert).publish_state(false);
id(bin_wsensor_1).publish_state(false);
id(bin_wsensor_2).publish_state(false);
id(bin_wsensor_3).publish_state(false);
id(bin_wsensor_4).publish_state(false);
turn_off_action:
- lambda: !lambda |-
id(var_water_leak) = false;
id(water_leak_alert).publish_state(false);
id(bin_wsensor_1).publish_state(false);
id(bin_wsensor_2).publish_state(false);
id(bin_wsensor_3).publish_state(false);
id(bin_wsensor_4).publish_state(false);
# If water leak detected, valves can't be opened util the alert "id(reset_water_leak)" is reset
cover:
- platform: time_based
name: "Cold Water Control"
id: cov_cold_water
open_action:
- lambda: |-
if (id(water_leak_alert).state){
ESP_LOGD("NotAllowed", "Water LEAK Alert!");
id(cov_cold_water).position = 0.0;
id(cov_cold_water).current_operation = COVER_OPERATION_IDLE;
id(cov_cold_water).publish_state();
} else {
id(cold_open).turn_on();
id(var_cold_open) = true;
}
open_duration: 7s
close_action:
- switch.turn_on: cold_close
- lambda: |-
id(var_cold_open) = false;
close_duration: 7s
stop_action:
- switch.turn_off: cold_open
- switch.turn_off: cold_close
- platform: time_based
name: "Hot Water Control"
id: cov_hot_water
open_action:
- lambda: |-
if (id(water_leak_alert).state){
ESP_LOGD("NotAllowed", "Water LEAK Alert!");
id(cov_hot_water).position = 0.0;
id(cov_hot_water).current_operation = COVER_OPERATION_IDLE;
id(cov_hot_water).publish_state();
} else {
id(hot_open).turn_on();
id(var_hot_open) = true;
}
open_duration: 7s
close_action:
- switch.turn_on: hot_close
- lambda: |-
id(var_hot_open) = false;
close_duration: 7s
stop_action:
- switch.turn_off: hot_open
- switch.turn_off: hot_close
Currently config and custom board under development
I will update post when I create new config.
Hardware:
UPDATE 1:
-
New code.
-
New photos
-
Now hardware can open electric door lock
The idea is to use WiFi Presence detection + ESP32 BLE tracker to open door when user just showed up on home WiFi network and BLE device near the door (not yet implemented)