Owner: Taylor tmfinnell@gmail.com Tags: Build, ESPHome
Create a simple sprinkler controller with 4 zones. Each zone should have a manual watering button. The controller should integrate with ESPHome and be fully local with no cloud dependencies.
Serial Converter Adapter Module | https://www.amazon.com/dp/B07D6LLX19?psc=1&ref=ppx_yo2ov_dt_b_product_details |
---|---|
4 channel relay with ESP8285 | https://www.amazon.com/dp/B089QD5CT6 |
24VAC transformer | https://www.amazon.com/dp/B08VW5XVVN |
Project Box | |
18 gauge wire |
The board linked above is a Tuya/SmartLife compatible board. Tuya, a Chinese company offers a free-to-brand turnkey smart home solution to anyone. Using their offer is dead-simple, since everything can be done by clicking through the Tuya web page, from choosing your pre-designed products or pre-programmed WIFI-modules (mostly ESP8266) to building your own app. In the end, this has resulted in as they claim over 11 000 devices 'made' by over 10 000 vendors using Tuya’s firmware and cloud services. (1)
Functionality is tied to overseas servers and cloud functionality.
Since there is a ESP 8285
chip on the board we are able to flash ESPHome.
-
Don’t plug anything into power or your computer yet.
-
Solder pins to the board for
GND
TXD
andRXD
. -
Make the following connections from your soldered pins to the serial module
Board | Serial Module |
---|---|
G | GND |
T | RXD |
R | TXD |
-
Plug the serial module into a USB port on your computer that you will use to flash. Do not connect the board to 5V power yet.
-
While pressing and holding the
CH1
button on the board connect the 5V USB power. This puts the chip in flashing mode. Continue to hold the button. -
In a terminal run the following (while holding the button still):
esptool.py flash_id
- You should see output similar to the following
esptool.py v4.6.2
Found 2 serial ports
Serial port /dev/ttyUSB0
Connecting.............................
Detecting chip type... Unsupported detection protocol, switching and trying again...
Connecting...
Detecting chip type... ESP8266
Chip is ESP8285N08
Features: WiFi, Embedded Flash
Crystal is 26MHz
MAC: 34:ab:95:00:3d:56
Uploading stub...
Running stub...
Stub running...
Manufacturer: 51
Device: 4014
Detected flash size: 1MB
Hard resetting via RTS pin...
-
If you see the above you may flash your firmware. Make sure the firmware is in the “Legacy Format” for ESPHome
-
Follow the same steps as above. Hold
CH1
while applying power and while still holding the button run the following:
esptool.py --port /dev/ttyUSBX write_flash --flash_mode dout --flash_size 1MB 0x0 sprinkler-controller-v2.bin
The board can run on 24VAC according the the amazon page. So I powered the board directly from the transformer. I ran one leg of the transformer power to the the COM
port of each relay. I ran the other leg to the common wire of the sprinkler system (represented by the short white wire in the image above). Each zone wire goes goes to the NO
terminal on the relay.
The 24VAC will be spliced into the open connectors on the WAGOs.
Once flashed you may integrate into ESPHome and Home Assistant. The configuration I used for the firmware I flashed is as follows:
esphome:
name: sprinkler-controller-v2
friendly_name: Sprinkler Controller v2
esp8266:
board: esp8285
# Enable logging
logger:
baud_rate: 0
# Enable Home Assistant API
api:
encryption:
key: "<snip>"
ota:
password: "<snip>"
#[23:01:28][C][tuya:056]: Datapoint 1: switch (value: OFF)
#[23:01:28][C][tuya:056]: Datapoint 2: switch (value: OFF)
#[23:01:28][C][tuya:056]: Datapoint 3: switch (value: OFF)
#[23:01:28][C][tuya:056]: Datapoint 4: switch (value: OFF)
#23:01:28][C][tuya:058]: Datapoint 7: int value (value: 0)
#[23:01:28][C][tuya:058]: Datapoint 8: int value (value: 0)
#[23:01:28][C][tuya:058]: Datapoint 9: int value (value: 0)
#[23:01:28][C][tuya:058]: Datapoint 10: int value (value: 0)
#[23:01:28][C][tuya:056]: Datapoint 13: switch (value: OFF)
#[23:01:28][C][tuya:056]: Datapoint 101: switch (value: OFF)
#[23:01:29][C][tuya:062]: Datapoint 102: enum (value: 0) # Relay mode, probably
#[23:01:29][C][tuya:058]: Datapoint 103: int value (value: 5)
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
manual_ip:
static_ip: 192.168.30.39
gateway: 192.168.30.1
subnet: 255.255.255.0
ap:
ssid: "Relay Fallback Hotspot"
password: "<snip>"
captive_portal:
uart:
rx_pin: GPIO3
tx_pin: GPIO1
baud_rate: 9600
tuya:
sensor:
- platform: uptime
name: Uptime
switch:
- platform: "tuya"
name: "Relay 1"
switch_datapoint: 1
internal: true
id: z1
restore_mode: ALWAYS_OFF
- platform: "tuya"
name: "Relay 2"
internal: true
switch_datapoint: 2
id: z2
restore_mode: ALWAYS_OFF
- platform: "tuya"
name: "Relay 3"
switch_datapoint: 3
internal: true
id: z3
restore_mode: ALWAYS_OFF
- platform: "tuya"
name: "Relay 4"
switch_datapoint: 4
internal: true
id: z4
restore_mode: ALWAYS_OFF
sprinkler:
- id: sprinkler_ctrlr
main_switch: "Sprinklers"
auto_advance_switch: "Sprinklers Auto Advance"
valve_overlap: 5s
valves:
- valve_switch: "Front Yard"
enable_switch: "Enable Front Yard"
run_duration_number: "Front Yard Sprinkler Duration"
valve_switch_id: z1
- valve_switch: "Back Yard"
enable_switch: "Enable Back Yard"
run_duration_number: "Back Yard Far Sprinkler Duration"
valve_switch_id: z2
text_sensor:
- platform: version
name: Firmware Version
hide_timestamp: true
filters:
- lambda: |-
return std::string("sprinkler-controller-v1");
- platform: wifi_info
ip_address:
name: IP
ssid:
name: SSID
bssid:
name: BSSID
- platform: template
name: Time Left
lambda: |-
char buf[128];
if (id(sprinkler_ctrlr).time_remaining_active_valve().has_value()) {
sprintf(buf, "%u sec.", id(sprinkler_ctrlr).time_remaining_active_valve().value());
} else {
// the controller is NOT running
sprintf(buf, "%s", "Idle");
}
return std::string(buf);
- platform: template
name: Active Zone
lambda: |-
char buf[128];
if (id(sprinkler_ctrlr).time_remaining_active_valve().has_value()) {
int val = id(sprinkler_ctrlr).active_valve().value();
if(val == 0){
return std::string("Front Yard");
}
else if(val == 1){
return std::string("Back Yard");
} else {
return std::string("Unknown Zone");
}
} else {
// the controller is NOT running
sprintf(buf, "%s", "None");
}
return std::string(buf);