DIY PetKit feeder local integration to Home Assistant via ESPHome

Hi all,

I want to tell you about my personal experience of modernizing cat feeders from PetKit - Fresh Element Mini. And I hope that my rough English will not make too much problem for you to read this post :slight_smile:

Background

Spoiler

I have 2 cats at my place. My wife and I sometimes go to our relatives for several days. And we have a feeding problem: cats compete with each other in eating food, as a result, if you pour a lot of food, they eat as much as possible at a time, and then return the excess along with the wool.

About a year ago, it was decided to try to get out of the situation with an automatic feeder.

With this feeder you can set up a profile for several cats, taking into account the calorie content of the feed, etc. It has a nice design, convenient application with notifications and remote control. There is also a button for manual feed dispensing. When pressed and held, the feed is poured into the bowl. It is worth letting go - the feeder stops.

In general, I am more than satisfied with the feeder. It works as expected. If the Internet is gone, it continues to dispense feed on a schedule.

But there is a problem: Sometimes the feeder signals a loss of connection with the PetKit servers. In this case, the feeder usually just continues to work properly.

During the year of owning this device, I had a situation 2 times when the feeder went offline and the feeding did not happen. Although when you press the manual feed button, the feed dispensing. So, apparently, the data on the feeding schedule was lost. To fix it, you had to reset the settings of the feeder, connect it via a mobile HotSpot, wait for a successful connection and then reset it again and connect to your home WiFi.

And if these steps 2 times a year do not cause any particular problems, then the likelihood of leaving cats without food for 3-5 days disappoints me. And the saddest thing is that you can’t do anything until you get home.

In general, a cardinal decision was made to change something. But what? The feeder as whole suits, minus annoying mistakes 2 times a year. Other feeders have the same functionality, but the problems are most likely exactly the same.

Now, if I could somehow connect it to the Home Assistant and locally send a signal to dispense food … And then BAM - I found the next article: Petoneer Nutri Smart Pet Feeder where a person reviews a similar device and then reflashes it WiFi module TYWE3S (which is based on ESP8266) and transfers full control of the feeder to its Home Assistant server.

Well, and how am I worse?

I found a video of the disassembling of the PetKit feeder (by the way, here it is: YouTube) and realized that the situation is similar. A similar antenna is based on the ESP8266. In my case, it was the ESP-WROOM-02 module. In general, you can just replace the firmware and …

And completely lose all available opportunities, permanently deprive the feeder of communication with the PetKit servers, deprive yourself of control via a mobile application, portioned food delivery to cats, etc. turning a smart device into a shadow of itself. It will just simulate a manual push of the feed button based on a command from HA and that’s it.

It won’t work that way. It was decided that the feeder should remain fully functional. The option with a re-flashing of ESP-WROOM-02 has disappeared. But what prevents us from putting your ESP8266 internally? We can power it from any suitable power supply on the mainboard and simulating a manual button press in the same way?

Preparation

Required:

  1. Phillips screwdriver
  2. Plastic spatula/spudger
  3. ESP8266 (in my case, this is NodeMCU by Lolin)
  4. Soldering iron
  5. Wires
  6. 2pin + 4pin or 6pin connectors (optional)
  7. bravery
  8. Stupidity

Disassemble

  1. Take the feeder, disconnect the bowl
  1. At the bottom, unscrew 2 screws: the 1st holds the backup power compartment cover, the 2nd holds the back wall
  1. Using a spudger, carefully detach the back half from the front and disconnect the cable. This process is well illustrated in the video: YouTube
  1. Remove the gray casing covering the mainboard and reveal the object of torture
  1. We remember where which wires go, just in case we take a photo and write it down in a notebook

  2. Gently detach the feed lid. It is secured with two pins on a leg with rubberized ears

  1. Unscrew 4 more screws from the bottom and we can take out the gray box with the engine. We remove it carefully
  1. You are gorgeous

Inventory

  1. Optocoupler sensor for the condition of the cover (which was in step 6 of the analysis).
Photo
  1. Optocoupler sensor of the condition of the motor (reads interruptions caused by the comb).
Photo
  1. Motor.
Photo
  1. Optical feed level sensor (we partially removed it together with the rear wall).
Photo
  1. The mainboard itself.
Photo
  1. The rest of the junk (buzzer, alarm diode, cover opening motor).

Connection

After a small investigation of the mainboard I managed to find out where to solder in order to achieve success:

  1. Power supply (3.3v or 6v depending on your controller)
  2. GND
  3. Manual feed - 5th leg (GPIO13)
  4. Optical feed level sensor
  5. Optocoupler of the state of the food supply cover
  6. Optocoupler of the impeller of the motor

On the side of my Chinese NodeMCU, I soldered like this:

  1. Power - Vin (on this pin the LM1117 regulator is set to 3.3v).
  2. Earth - GND
  3. Optical feed level sensor - D0
  4. Optocoupler of the state of the lid of the food supply - D1
  5. Optocoupler of the status of the lid of the food supply - D2
  6. Feed button - D3

The photo shows that while I was attaching the connector, I mixed up the colors. Green turned red, yellow turned orange, etc. But this is not important, although it is very confusing. Fortunately, the dero connector can only be inserted in one position.

Firmware

It’s time to flash NodeMCU using ESPHome. Otherwise, after collection, access will be somewhat limited.

Configuration in details:

1. Optical feed level sensor - D0

 binary_sensor:
  - platform: gpio
    name: "PetKit Food level state"
    device_class: problem
    pin: 
      number: D0
      inverted: true
    filters:
      - delayed_off: 120000ms

The signal is inverted. If there is not enough feed, it is interrupted for a fraction of a second every 10 seconds until you add food. As a result, I had to add an inversion and make a delayed_off for 20 seconds. If the signal is interrupted, the sensor signals a lack of feed and remains in this position for 20 seconds. If during this time it receives another signal interrupt, the counter is reset to zero. If there is no signal interruption for more than 20 seconds, the feed has been filled up.

2. Optocoupler of the state of the lid of the food supply - D1

  - platform: gpio
    name: "PetKit Cap state"
    pin: 
      number: D1
      inverted: true
    filters:
      - delayed_on_off: 100ms
      - delayed_off: 2000ms

The signal is inverted. When the lid is closed, an interrupt occurs once per second. The feeder is actively checking to see if someone is trying to break it. I cannot explain it otherwise. I added delayed_on_off for 100 milliseconds to ignore short changes in signal to not clutter up the history. Now it the signal will be ignored as long as it is shorter than 100 milliseconds. With a real trigger, the interrupt will last for a few seconds - it means that the lid is open.
UPD: delayed_off for 2 seconds added to avoid bouncing state during cap opening.

3. Optocoupler of the state of the lid of the food supply - D2

  - platform: gpio
    name: "PetKit Motor state"
    device_class: moving
    pin: 
      number: D2
      inverted: true
    filters:
      - delayed_on_off: 100ms
      - delayed_off: 2000ms

The signal is inverted. The optocoupler does not send any signal changes until the motor is moving. During motor rotating the impeller of the motor passes through the Optocoupler approximately once per second. The signal is intermittent. To avoid this, a 2-second delay has been added for the response to the signal off. Also, I added delayed_on_off for 100 milliseconds just in case. It’s not really needed there.

4. Feed button (sensor) - D3

  - platform: gpio
    name: "PetKit Feed button state"
    pin: 
      number: D3
      allow_other_uses: true
      inverted: true

Well, everything is simple, the signal is inverse, we read the manual pressing of the button. Just because we can.

5. Feed button (switch) - D3

switch:
  - platform: gpio
    pin: 
      number: D3
      allow_other_uses: true
      inverted: true
    id: relay
    name: "PetKit Feed button"
    icon: "mdi:shaker"
    on_turn_on:
      #2000    4g
      #4000    8g
      #20000ms 50g
    - delay: 4000ms #50g
    - switch.turn_off: relay

Actually, the highlight of the program is the imitation of manually pressing the button. The same inverted signal. When you press the button, you need to hold it, otherwise, the feeder will ignore it as an accidental pressing. Pressing for 2 seconds gives 4 grams of feed, 4 seconds - 8 grams, 20 seconds - 50 grams.

The final configuration file looks like this:

esphome:
  name: petkit-feeder-esp8266
  platform: ESP8266
  board: nodemcuv2

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:
  password: *********************************

wifi:
  ssid: "***************************"
  password: "***********************"

#uncomment next 2 lines if you want to have web server on your esp8266
#web_server: 
#  port: 80

binary_sensor:
  - platform: gpio
    name: "PetKit Food level state"
    device_class: problem
    pin: 
      number: D0
      inverted: true
    filters:
      - delayed_off: 20000ms
    
  - platform: gpio
    name: "PetKit Cap state"
    device_class: opening
    pin: 
      number: D1
      inverted: true
    filters:
      - delayed_on_off: 100ms
      - delayed_off: 2000ms
    
  - platform: gpio
    name: "PetKit Motor state"
    device_class: moving
    pin: 
      number: D2
      inverted: true
    filters:
      - delayed_on_off: 100ms
      - delayed_off: 2000ms
    
  - platform: gpio
    name: "PetKit Feed button state"
    pin: 
      number: D3
      allow_other_uses: true
      inverted: true

switch:
  - platform: gpio
    pin: 
      number: D3
      allow_other_uses: true
      inverted: true
    id: relay
    name: "PetKit Feed button"
    icon: "mdi:shaker"
    on_turn_on:
      #2000    4g
      #4000    8g
      #20000ms 50g
    - delay: 4000ms
    - switch.turn_off: relay

If you want to send grams directly to the ESP - read Drealine message: Link

Assembly

I carefully glued my spy board next to the engine using hot-melt glue. Not elegant but should be enough.

Photo

The wire could be pulled through the native technological hole, but we are not looking for easy ways. Therefore, it was decided that it was necessary to dig out a hole with a broken clerical knife.

Photo

We screw the mainboard into place, connect all the wires in the reverse order + our spy board.

Photo

We close it with a decorative casing. I had to cut it slightly, otherwise, the wire stretching to the new “technological” hole was slightly pinched. By the way about it - I also glued it over, just because I can.

Photo

Result

Actually from the outside nothing has changed at all.

Photo

However, now the smart home finds the petkit-feeder-esp8266 device in the local WiFi network and allows you to feed cats or find out the current status of the device without any problems. You can save the log of events associated with the feeder in the history and be able to analyze whether the feeding was completed.

Capture2

Now, in case of a glitch with a fallen-off server and not-fed cats will appear again I can set up an alert on the phone and/or press the feed button via automation. Like a safety system.

In the end, the project goal was achieved. The feeder received a couple of new features and did not lose any of its function and/or good looks. And only a hastily made technological hole gives out the hand of the master.

In case if you will have any questions - don’t hesitate to ask.
Or if you will have any ideas how this project can be improved - welcome to discussion.

Thank you.

14 Likes

Hi, great project!

I was looking for a solution like this and I think I will purchase the Petkit Fresh Element Mini or the PetLibro cat feeder. I am comfortable on the software side but not on the hardware side. If I may, a couple of questions before I embark on this adventure:

  • how did you figure out the wiring? Would it be as easy to figure out on any ‘dumb’ feeder (e.g the PetLibro one)?
  • why did you go with the Petkit feeder which seems to be pretty ‘smart’ already (it has WiFi etc)?

Thanks!

Hi, sure.

I used only a multimeter to find the correct joints. It’s not too difficult. I made it in 1-2 hours.
I also don’t have any normal knowledge of electronics or schemas. So I think in general it’s manageable.
Only 1 thing - you need to be sure that all signals will have compatible voltage. For ESP8266 it should be 3,3v.

Why did I choose Petkit? Actually, I bought it before I start using HA. So initially I didn’t have in mind to integrate it to HA. And I Xiaomi fan. Petkit, as far as I know, was affiliated with Xiaomi somehow, so for me, it was an obvious choice.

2 Likes

Buddy, I think I screwed up, I thought I could directly flash it with tasmota but apparently, it’s not that simple. Now I’m stuck, the backup I created was corrupted.

Would you be able to dump the onboard ESP8266 firmware and share it with me?
I think the RESET pin (top left) needs to be grounded when dumping
Many thanks.

never mind, it turned out my dump was not corrupted.
here’s the onboard ESP8266 chip dump, if anyone run into the same situation.

1 Like

Is it possible to flash this onto the esp on board and not do the NodeMCU spy board? I don’t need the app if I have full local control and it would be one less thing to go bad in the long run.

1 Like

Hi, I think it’s possible.
Onboard chip - ESP-WROOM-02.
You can try to find how to flash it on google.
As far as I understood - it’s regular ESP-8266 but in a bit different form factor.

ESP-WROOM-02 pinout

Hi @AndreyShpilevoy,

Glad to see this integration, it’s amazing and very powerfull, thank’s for sharing :slight_smile:

Your screenshot show sensors from Cloud, it’s the custom integration of this : GitHub - hasscc/petkit: 🐱 Petkit feeder components for HomeAssistant ?

This is a really fun project and I’m interested to see if I can impliment the same nodeMCU spyboard on a Nutri Pet feeder. Can you elaborate a little more on how you worked out which button does what, what GPIOs to attach it to on the nodeMCU?

Yes, but mine is a bit outdated. I will update it with the latest version soon.

I just checked with a multimeter which signal (high/low) I will have when a lead is open or closed, which signals I will have when the motor is spinning etc.
For NodeMCU pins - just used random GPIO pins based on PinOut.

The onboard ESP8266 is only used as a WiFi chip, it doesn’t handle the GPIOs I think, there’s an ARM processor onboard that handles it. We probably would need to crack that ARM chip’s firmware to do an offline integration.

Yep, or you need to find out how to connect the existing ESP chip to signal lines with physical wiring.

Unfortunately, I don’t have enough experience to crack ARM chip’s firmware, so I use an extra esp8266 chip to handle this integration.

I don’t know if it’s possible. Number Component — ESPHome, normally, you can set a number component to interact with the ESP for grams of feed.

It will be usefull.

Bare with my ignorance but I’m not sure how you do this? Is the pet feeder powered via the mains when you do this test? I presume one of the probes is attached to a groud and the other to the GPIO pad? And what’s the multimetre set to? I’m keen to know what sort of test this is called so I can Google it further and learn more.

Hi @AndreyShpilevoy, thank’s again for your DIY tuto. I finished to implement ESP8266 on my petkit and it’s work like a charm.

To improve interaction, I perform research and found that how send grams directly to the ESP.

To make this :

  1. Create an input number :
petkit_grammage:
  name: Petkit - Grammage
  min: 5
  max: 50
  step: 5
  unit_of_measurement: g
  1. Create a template who make a multiplication gram * number of millisecond for each. For me, 2000ms corresponding to 5g.
- platform: template
  sensors:
    grammage_vers_esp:
      friendly_name: Grammage vers ESP
      unit_of_measurement: "ms"
      value_template: >
        {% set grammage = states.input_number.petkit_grammage.state | int %}
        {{ grammage * 400 }}
  1. Adding the sensor on the ESP Conf :
sensor:
  - platform: homeassistant
    name: "Valeur ms dans ESP "
    entity_id: sensor.grammage_vers_esp
    id: var_grammage
  1. Change the delay on switch define of the ESP by using lambda function :
switch:
  - platform: gpio
    pin: 
      number: D3
      inverted: true
    id: relay
    name: "Petkit - Actionneur croquettes"
    icon: "mdi:shaker"
    on_turn_on:
      #2000    4g
      #4000    8g
      #20000ms 50g
    - delay: !lambda 'return id(var_grammage).state;'
    - switch.turn_off: relay

That’s all. Flash the ESP via your prefered option (OTA or USB) and you can set grams via HA to the ESP.

2 Likes

Great!
I added a link to this post in the first message.

Mainboard powered.
Both multimeter probes on both pins that related to the necessary sensor.
Called action that was most interesting for me - tracked results on multimeter.

This is a fully offline solution, right? Of course you need to block connections from the feeder to the internet, but it will be fully operational.

The way that I described in the first post - fully local.
You can think about it like any other regular ESPHome device.

I’ve to set delayed_off to 120000ms (2min). With the delay of 20000ms, the binary_sensor switch to Problem > OK and OK > Problem in 1 second while the compartment is empty.