VSON WP8621_V12 Fish Feeder

I’ve replaced the original chipset of my VSON WP8621_V12 Fish Feeder.
It’s a work in progress so bear with me and I hope some of you can help me out.
This is the top view of the device:


This is the bottom view of the device:

This is the inside view of the device:

This is the original fron of the PCB:

This is the back of the PCB:

I’ve desoldered the WIFI001_V20 chipset and replaced it with a ESP12E:

With my multimeter set to continuity test I was able to figure out the GPIO-usage.

ESP12-E Pins used
=================
GND
GPIO15 	Open/close detection
GPIO2 	N/C
GPIO0 	Button (rear)
GPIO4 	LED (blue)
GPIO5 	LED (red)
GPIO3 	RX
GPIO1 	TX

GPIO6	N/C
GPIO8	TC118S
GPIO10	TC118S
GPIO9	N/C
GPIO7	N/C
GPIO11	N/C

VCC		VCC
GPIO13	N/C
GPIO12	N/C
GPIO14	Food indicator
GPIO16	N/C
Enable	
ADC0	N/C
RST 	N/C

I’ve created the following ESPHome Configuration:

substitutions:
  name: "wp8621_fishfeeder"
  friendly_name: "WP8621_FishFeeder"

esphome:
  name: "${name}"
  friendly_name: "${friendly_name}"

esp8266:
  board: esp12e
  restore_from_flash: true

preferences:
  flash_write_interval: 0s

logger:

packages:
  api: !include ./includes/api.yaml
  ota: !include ./includes/ota.yaml
  wifi: !include ./includes/wifi.yaml
  time: !include ./includes/time.yaml
  web_server: !include ./includes/web_server.yaml
  text_sensor: !include ./includes/text_sensor.yaml
  sensor: !include ./includes/sensor.yaml
  switch: !include ./includes/switch.yaml
  binary_sensor: !include ./includes/binary_sensor.yaml

captive_portal:

output:
  - platform: gpio
    id: led_red_led
    pin: 
      number: GPIO5

light:
  - platform: binary
    name: "Red Light"
    output: led_red_led
    id: red_led

binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO0
      mode: INPUT_PULLUP
      inverted: true
    name: "Button"
    on_press:
      - light.turn_on:
          id: red_led
      - switch.turn_on:
          id: motor_switch
      - delay: 12.5s
      - switch.turn_off:
          id: motor_switch
      - light.turn_off:
          id: red_led

switch:
  - platform: gpio
    pin: 
      number: GPIO10
      inverted: false
    id: motor_switch
    name: "Motor Switch"

status_led:
  pin:
    number: GPIO4

I have to do some measurements on GPIO15, the open/close detection. The switch itself is a normally closed one (when the button isn’t pressed, there is a circuit made) connected to ground and this is causing an issue. GPIO15 is being used by the ESP during boot and with the open/close detection being active (button pressed because the feeding bay is retracted) the ESP12E will not boot. Is there any way to bypass this? The switch can act as a counter and it will also allow to stop the motor when the bay is finished with it’s routine.

Also there is food indicator that gave a warning when it was running out of food. This should be connected to GPIO14 and it looks like the same principle as a IR proximity sensor; an IR emmitor and an IR reciever (LED formfactor). I haven’t yet got that running.

Any help would be appreciated.

This was an interesting project. I’ve made some adjustments:

  • The switch wired near J2 and connected to GPIO15 gives an issue with the ESP12E. The feeding bay in it’s closed state won’t allow the ESP to boot. When removed the same issue arises. I’ve resolved this issue replacing the switch with a 4,7Ohm resistor.
  • The desoldered switch has been connected to GPIO3 (RX) and ground with a pull-up (4,7Ohm resistor connected to VCC and GPIO3).

For the curious ones: I’ve bought my WB8621 at AliExpress (https://a.aliexpress.com/_EQqznvf)

The ESPHome configuration looks as follows:

substitutions:
  name: "wp8621_fishfeeder"
  friendly_name: "WP8621_FishFeeder"

esphome:
  name: "${name}"
  friendly_name: "${friendly_name}"
  on_boot:
    priority: -10
    then:
      - delay: 2s  # Give the sensor a moment to stabilize after boot
      - if:
          condition:
            binary_sensor.is_on: open_close_sensor
          then:
            - switch.turn_on: motor_switch

esp8266:
  board: esp12e
  restore_from_flash: true

preferences:
  flash_write_interval: 0s

logger:

packages:
  api: !include ./includes/api.yaml
  ota: !include ./includes/ota.yaml
  wifi: !include ./includes/wifi.yaml
  time: !include ./includes/time.yaml
  web_server: !include ./includes/web_server.yaml
  text_sensor: !include ./includes/text_sensor.yaml
  sensor: !include ./includes/sensor.yaml
  switch: !include ./includes/switch.yaml

captive_portal:

# Define the red LED as a binary output
output:
  - platform: gpio
    id: led_red_led
    pin: 
      number: GPIO5

# Control the red LED via the web interface
light:
  - platform: binary
    name: "Red Light"
    output: led_red_led
    id: red_led

# Define binary sensors (button, Open/Close sensor, and Food Level Indicator)
binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO0
      mode: INPUT_PULLUP
      inverted: true
    name: "Button"
    on_press:
      - switch.turn_on:
          id: motor_switch

  - platform: gpio
    pin: 
      number: GPIO3
      inverted: true
    name: "Open/Close Sensor"
    id: open_close_sensor
    on_state:
      - if:
          condition:
            binary_sensor.is_on: open_close_sensor
          then:
            - switch.turn_on: motor_switch
          else:
            - delay: 1s
            - switch.turn_off: motor_switch

  - platform: gpio
    pin: 
      number: GPIO14
      mode: INPUT_PULLUP
      inverted: false
    name: "Food Level Sensor"
    id: food_level_sensor
    device_class: "problem"  # Marks the sensor as an indicator of a problem (low food level)
    on_state:
      - if:
          condition:
            binary_sensor.is_on: food_level_sensor
          then:
            - logger.log: "Food level is low!"
          else:
            - logger.log: "Food level is sufficient."

# Define the switch for controlling the motor
switch:
  - platform: gpio
    pin: 
      number: GPIO10
      inverted: false  # Adjust this based on the TC118S control logic
    id: motor_switch
    name: "Motor Switch"
    on_turn_on:
      - light.turn_on: red_led
    on_turn_off:
      - light.turn_off: red_led

# Use the blue LED as a Wi-Fi status light
status_led:
  pin:
    number: GPIO4

This is (probably) the final configuration of the (modified) WB8621 FishFeeder:

substitutions:
  name: "wp8621_fishfeeder"
  friendly_name: "WP8621_FishFeeder"

esphome:
  name: "${name}"
  friendly_name: "${friendly_name}"
  on_boot:
    priority: -10
    then:
      - delay: 2s
      - if:
          condition:
            binary_sensor.is_on: open_close_sensor
          then:
            - switch.turn_on: motor_switch

esp8266:
  board: esp12e
  restore_from_flash: true

preferences:
  flash_write_interval: 0s

logger:
  
api:
  encryption:
    key: "{{API key}}"			# Replace with the actual API encryption key.

ota:
  - platform: esphome
    password: "{{password}}"	# Replace with the OTA update password.

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "WB8621 Fallback Hotspot"
    password: "{{password}}"	# Replace with a password for the fallback AP.

captive_portal:
  
time:
  - platform: homeassistant
    id: homeassistant_time		# Sync time with Home Assistant's time service.
  - platform: sntp
    id: sntp_time				# SNTP is a simpler form of NTP for syncing time with NTP servers.
    timezone: "{{timezone}}"	# Replace with your time zone (e.g., 'Europe/Amsterdam').
    servers:					# NTP servers for time synchronization.
     - "{{NTP server #1}}"		# Replace with actual NTP server.
     - "{{NTP server #2}}"
     - "{{NTP server #3}}"

sensor:
  - platform: wifi_signal
    name: "WiFi - Signal"
    update_interval: 60s
    entity_category: "diagnostic"

  - platform: uptime
    name: "System - Uptime"

output:
  - platform: gpio
    id: led_red_led
    pin: 
      number: GPIO5

light:
  - platform: binary
    name: "Red Light"
    output: led_red
    id: red_led

globals:
  - id: open_close_counter
    type: int
    restore_value: yes
    initial_value: '0'

sensor:
  - platform: template
    name: "Open/Close counter"
    id: open_close_counter_sensor
    unit_of_measurement: "times"
    accuracy_decimals: 0
    lambda: |-
      return id(open_close_counter);

binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO0
      mode: INPUT_PULLUP
      inverted: true
    name: "Button"
    filters:
      - delayed_on: 15ms 		# Debounce the button to avoid false triggers.
    on_press:
      - switch.turn_on:
          id: motor

  - platform: gpio
    pin: 
      number: GPIO3
      inverted: true
    name: "Open/Close sensor"
    id: open_close_sensor
    on_state:
      - if:
          condition:
            binary_sensor.is_on: open_close_sensor
          then:
            - switch.turn_on: motor
            - lambda: |-
                id(open_close_counter) += 1;
                id(open_close_counter_sensor).publish_state(id(open_close_counter));
          else:
            - delay: 1s                              # Delay for 1 second so the bay is in the feeder.
            - switch.turn_off: motor

  - platform: gpio
    pin: 
      number: GPIO14
      mode: INPUT_PULLUP
      inverted: false
    name: "Food level sensor"
    id: food_level_sensor
    device_class: "problem"            # Classify this as a problem entity in Home Assistant.
    on_state:
      - if:
          condition:
            binary_sensor.is_on: food_level_sensor
          then:
            - logger.log: "Food level is low!"
          else:
            - logger.log: "Food level is sufficient."

switch:
  - platform: gpio
    pin: 
      number: GPIO10
      inverted: false
    id: motor
    name: "Motor"
    restore_mode: ALWAYS_ON
    on_turn_on:
      - light.turn_on: red_led
    on_turn_off:
      - light.turn_off: red_led

  - platform: restart
    name: "System - Restart"

  - platform: safe_mode
    name: "System - Safe mode"

status_led:
  pin:
    number: GPIO4

I’ve created a simple automation that allows you to set the time of feeding and the amount of servings the fish need.
For this automation to work you’ll need to create two helpers within Home Assistant:

  • A Time helper (Date and/or Time → set the input to Time,
  • A Number helper (Number → set minimum to 1 and maximum to 10 or something)

You should replace input_datetime.{{fish_feedingtime}}, input_number.{{fish_meals}} and switch.{{motor fishfeeder}} with the entity ID’s applicable to your situation.

alias: Fish Feeding
description: ""
trigger:
  - platform: time
    at: input_datetime.{{fish_feedingtime}}
condition: []
action:
  - repeat:
      count: "{{ states('input_number.{{fish_meals}}') | int }}"
      sequence:
        - target:
            entity_id:
              - switch.{{motor fishfeeder}}
          action: switch.turn_on
          data: {}
        - wait_for_trigger:
            - platform: state
              entity_id: switch.{{motor fishfeeder}}
              to: "off"
mode: single

I’ve also created a Card Configuration for your dashboard based, you should have Mushroom Cards installed.
You should replace switch.{{motor fishfeeder}}, binary_sensor.{{food_level_sensor}}, input_number.{{fish_feedingtime}} and input_datetime.{{fish_meals}} with the entity ID’s applicable to your situation.

type: vertical-stack
cards:
  - type: horizontal-stack
    cards:
      - type: custom:mushroom-title-card
        title: WP8621 FishFeeder
        subtitle: ''
        title_tap_action:
          action: none
        subtitle_tap_action:
          action: none
  - type: horizontal-stack
    cards:
      - type: custom:mushroom-entity-card
        entity: switch.{{motor fishfeeder}}
        tap_action:
          action: toggle
        hold_action:
          action: none
        double_tap_action:
          action: none
        name: Feed fish manually
        primary_info: name
        secondary_info: none
        icon: mdi:archive
  - type: horizontal-stack
    cards:
      - type: custom:mushroom-template-card
        primary: Food level
        secondary: >-
          {% if states('binary_sensor.{{food_level_sensor}}') 
          == 'on' %} Food level is low!

          {% elif states('binary_sensor.{{food_level_sensor}}') 
          == 'off' %} Food level is sufficient.

          {% endif %}
        icon: >-
          {% if states('binary_sensor.{{food_level_sensor}}') 
          == 'on' %} mdi:alpha-l-circle-outline

          {% elif states('binary_sensor.{{food_level_sensor}}') 
          == 'off' %} mdi:alpha-f-circle

          {% endif %}
        entity: binary_sensor.{{food_level_sensor}}
  - type: horizontal-stack
    cards:
      - type: custom:mushroom-number-card
        entity: input_number.{{fish_feedingtime}}
        fill_container: false
        name: Number of servings
        display_mode: buttons
        secondary_info: none
      - type: custom:mushroom-entity-card
        entity: input_datetime.{{fish_meals}}
        name: Feeding time
1 Like