I want to share my cat feeder and water fountain.
Before, I had a pretty similar set up but I had to move to ESP because ZigBee wasn´t so reliable and several times the feeder didn’t work, but now that is all in the past.
So, the setup is an ESP8266 to control a 24VDC (can be 12VDC) motor and a 5VDC water pump (almost all the water cat fountain are 5VDC) and a PIR motion sensor to start the pump when is need it.
The part list is the following:
-
220VAC to 24VDC converter
-
220VAC to 5VDC converter
-
Two Push buttons
-
ESP8266 NodeMCU
-
2 Ralay Module
-
Generic PIR sensor
-
24 VDC (about 15 rpm)
-
5VDC water fountain
-
Cereal Dispenser
-
CNC Motor Jaw Shaft Coupler 5mm To 8mm Flexible Coupling (size depend on the shaft of the motor and the cereal dispenser)
-
Some DuPont cables
-
Some extra cables
-
Some patience…
Most of the code is on ESPHome, so is no need to be connected all the time to HA. I’m planning to add a clock module to the ESP8266 so in case of blackout it still has the time…
The ESPHome program has the following controls on HA use:
- First meal Time
- Second meal Time.
- Time duration of the feed motor (let say 15 sec each meal)
- Water time after motion is clear (let say 10 sec.)
- Feed Button
- Water Buton
Hope you enjoy it!!
ps. Some parts of the code is in spanish… just google the words so it make sense…
The code:
esphome:
name: cat-feeder
friendly_name: cat feeder
esp8266:
board: nodemcuv2
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "Vnvo3Jd6ufsdffsfdshgtfhtrhrth7AN8O8="
ota:
password: "5d1hdfhfgghfg7813c436a73a158"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Cat-Feeder Fallback Hotspot"
password: !secret wifi_password
captive_portal:
switch:
- platform: gpio
pin: D1
id: relay_agua
inverted: true
restore_mode: ALWAYS_OFF
- platform: template
id: ha_switch_agua
name: "HA switch agua"
optimistic: true
on_turn_on:
- logger.log: "############################# Power ON #############################"
- switch.turn_on: relay_agua
on_turn_off:
- logger.log: "############################# Power OFF #############################"
- switch.turn_off: relay_agua
- platform: template
id: water_on_delay
optimistic: true
on_turn_on:
- switch.toggle: ha_switch_agua
- delay: 240 sec
- if:
condition:
# Same syntax for is_off
binary_sensor.is_off: pir_sensor
then:
- switch.turn_off: ha_switch_agua
- switch.turn_off: water_on_delay
- platform: gpio
name: "relay"
pin: D7
id: relay
inverted: true
restore_mode: ALWAYS_OFF
# The following can be omitted
- platform: restart
name: restart
- platform: template
name: "HA Feed Button"
id: ha_feed_button
optimistic: true
on_turn_on:
- logger.log: "############################# Power ON #############################"
- switch.turn_on: relay
- switch.turn_on: water_on_delay
on_turn_off:
- logger.log: "############################# Power OFF #############################"
- switch.turn_off: relay
- text_sensor.template.publish:
id: ha_hora_encendido
state: !lambda |-
char str[17];
time_t currTime = id(homeassistant_time).now().timestamp;
strftime(str, sizeof(str), "%m-%d-%Y %H:%M", localtime(&currTime));
return { str };
# strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", localtime(&currTime));
number:
- platform: template
name: "Timepo agua despues de sin movimiento"
id: water_time_after_clear
optimistic: true
min_value: 0
max_value: 60
step: 5
mode: box
initial_value: 10
restore_value: true
- platform: template
id: duration
name: "duration"
optimistic: true
min_value: 1
max_value: 25
step: 1
mode: box
initial_value: 12
restore_value: true
- platform: template
name: "Hora 1"
id: hora_1
optimistic: true
initial_value: 7
min_value: 0
max_value: 24
step: 1
mode: box
- platform: template
name: "Hora 2"
id: hora_2
optimistic: true
initial_value: 19
min_value: 0
max_value: 24
step: 1
mode: box
- platform: template
name: "Minuto 1"
id: minuto_1
optimistic: true
initial_value: 30
min_value: 0
max_value: 60
step: 1
mode: box
- platform: template
name: "Minuto 2"
id: minuto_2
optimistic: true
initial_value: 30
min_value: 0
max_value: 60
step: 1
mode: box
binary_sensor:
##################################### agua############################
- platform: gpio
pin: D0
name: "PIR Sensor"
id: pir_sensor
device_class: motion
on_press:
- if:
condition:
and:
- lambda: 'return id(homeassistant_time).now().hour >= 7;'
- lambda: 'return id(homeassistant_time).now().hour <= 23;'
then:
- switch.turn_on: ha_switch_agua
on_release:
then:
- delay: !lambda "return ((id(water_time_after_clear).state * 1000));"
- if:
condition:
# Same syntax for is_off
binary_sensor.is_off: pir_sensor
then:
- switch.turn_off: ha_switch_agua
- platform: gpio
id: button_water
pin:
number: D2
inverted: true
filters:
- delayed_on: 50ms
- delayed_off: 50ms
on_press:
then:
- logger.log: "############################# Power on/off PRESS #############################"
- switch.toggle: ha_switch_agua
- delay: 240 sec
- if:
condition:
# Same syntax for is_off
binary_sensor.is_off: pir_sensor
then:
- switch.turn_off: ha_switch_agua
########################### fin agua############## inicio comida ########################
- platform: gpio
id: power_on_off
pin:
number: D3
inverted: true
filters:
- delayed_on: 400ms
- delayed_off: 50ms
on_press:
then:
- logger.log: "############################# Power on/off PRESS #############################"
- delay: 0.0 sec
- switch.turn_on: ha_feed_button
on_release:
then:
- switch.turn_off: ha_feed_button
interval:
- interval: 60sec
then:
- lambda: |-
float h1 = id(hora_1).state;
float m1 = id(minuto_1).state;
float hah = id(homeassistant_time).now().hour;
float ham = id(homeassistant_time).now().minute;
ESP_LOGD("main", "hora_1: %0.0f; minuto_1: %0.0f xxxxxxx HA_hora: %0.0f; HA_minuto: %0.0f; ",h1,m1,hah,ham);
- if:
condition:
or:
- and:
- lambda: 'return id(hora_1).state == id(homeassistant_time).now().hour ;'
- lambda: 'return id(minuto_1).state == id(homeassistant_time).now().minute;'
- and:
- lambda: 'return id(hora_2).state == id(homeassistant_time).now().hour;'
- lambda: 'return id(minuto_2).state == id(homeassistant_time).now().minute;'
then:
- lambda: ESP_LOGD("main", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
- lambda: ESP_LOGD("main", "Inicio");
- switch.turn_on: ha_feed_button
- delay: !lambda "return ((id(duration).state * 1000));"
- lambda: ESP_LOGD("main", "Fin");
- switch.turn_off: ha_feed_button
##################################################################################################
##################################################################################################
##################################################################################################
time:
- platform: homeassistant
id: homeassistant_time
# Text sensors with general information.
text_sensor:
# Expose ESPHome version as sensor.
- platform: version
name: Version
# Expose WiFi information as sensors.
- platform: wifi_info
ip_address:
name: IP
bssid:
name: BSSID
# human readable update text sensor from sensor:uptime
- platform: template
name: Uptime Human Readable
id: uptime_human
icon: mdi:clock-start
- platform: template
name: "Hora Encendido"
id: ha_hora_encendido
sensor:
- platform: wifi_signal
id: wifi_signal_db
name: wifi signal
update_interval: 60s
- platform: copy # Reports the WiFi signal strength in %
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "Signal %"
entity_category: "diagnostic"
# human readable uptime sensor output to the text sensor above
- platform: uptime
name: Uptime in Days
id: uptime_sensor_days
update_interval: 60s
on_raw_value:
then:
- text_sensor.template.publish:
id: uptime_human
state: !lambda |-
int seconds = round(id(uptime_sensor_days).raw_state);
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
return (
(days ? String(days) + "d " : "") +
(hours ? String(hours) + "h " : "") +
(minutes ? String(minutes) + "m " : "") +
(String(seconds) + "s")
).c_str();
Some Pictures: