petfeedd is a daemon for Raspberry Pi that will feed your pets. :)
Well, okay, obviously, it won't physically feed your pets. You'll still have to build the hardware part of the feeder. But it aims to wrap up the common functionality that pet feeders require into a format that can be reused for any number of feeder designs.
petfeedd provides:
-
A web interface for "programming" your feeder, that allows an arbitrary number of feeds of an arbitrary size.
-
A RESTful API that can be used to write third-party clients.
-
An auto-discovery protocol that can be used to find feeders on your network. Useful for writing third party clients.
-
A notification system that supports email, PushBullet and Twitter.
petfeedd is implemented predominantly in Python 3 using Flask and Peewee, with Vue.js and Bootstrap used for the web interface.
Let's have some common sense. This is a pet feeder. Do not expose it to the Internet. It implements no security on the web interface. There are no users or passwords or API keys. Again, it's a pet feeder, not a banking site. Keep it safely behind your firewall.
If you're truly paranoid, after configuring it you can disable the web interface and auto discovery system. Then it'll just run as usual.
petfeedd is reported to be working without modification on:
- Raspberry Pi Zero
- Raspberry Pi 3
- Raspberry Pi 3B v1.2
- Raspberry Pi 3B+
No matter which installation path you choose, the first step is to install Raspbian and configure to your liking.
If you just want to run petfeedd and don't want to go to all of the work below to run it from source, I maintain Docker images that are complete and ready for immediate use. To install this way:
-
Install Docker on your Raspberry Pi. You may need to log out and back in if you get permission errors.
-
docker pull peckrob/petfeedd-arm32v7:0.2.1
. Be patient, it will take a bit. -
sudo touch /opt/petfeedd.db && sudo chown pi: /opt/petfeedd.db
-
docker run --privileged -v /opt/petfeedd.db:/petfeedd/petfeedd.db -p 0.0.0.0:8080:8080 peckrob/petfeedd-arm32v7
Navigate to the IP of your Raspberry Pi on port 8080, and you should see petfeedd running. It takes a bit to start, so give it about 20-30 seconds to get going. It will run with the defaults, but in order for it to be useful, you'll need to configure it.
The reason we pass --privileged
to the container is to allow the container to
access the host's GPIO pins. The reason that we pass
-v /opt/petfeedd.db:/petfeedd/petfeedd.db
is to store the DB outside the
container.
The examples here are indended for the ARM processors on the Raspberry Pi, thus
the arm32v7
on the end of the image. I also build amd64
and arm32v6
images
as well, just replace arm32v7
with any of the below in every example above.
arm32v7
- Raspberry Pi 2/2B/3/3Barm32v6
- Raspperry Pi/Zeroamd64
- Intel x86
Timezones inside the Docker container are independent of timezones on the
device. Assuming you have run sudo raspi-config
and set the timezone properly,
unless you want to use UTC for your feeders you will need to bring
/etc/localtime
into the container.
$ docker run --privileged -v /etc/localtime:/etc/localtime -v /opt/petfeedd.db:/petfeedd/petfeedd.db -p 0.0.0.0:8080:8080 peckrob/petfeedd-arm32v7
To configure it, you have two options. You can either use environment variables passed to the Docker container or the config file. The config file is probably the easiest approach.
To configure using a config file, you'll create a config file at
/etc/petfeedd.conf
using the contents of the example config file above,
customized for your liking. Then, run the Docker container with the config file
mapped into the container. petfeedd should pick it up automatically.
$ docker run -d --privileged -v /opt/petfeedd.db:/petfeedd/petfeedd.db -v /etc/petfeedd.conf:/petfeedd/petfeedd.conf -p 0.0.0.0:8080:8080 peckrob/petfeedd-arm32v7
While the config file is probably the easiest approach, petfeedd will also read
from environment variables. Environment variables start with petfeedd
and
follow the convention expressed in the config file, with sections and keys
separated by underscores (_
). For example, to enable logging, you would pass
petfeedd_logging_enabled=1
to the Docker container:
$ docker run -d --privileged -v /opt/petfeedd.db:/petfeedd/petfeedd.db -e petfeedd_logging_enable=0 -p 8080:8080 peckrob/petfeedd-arm32v7
IMPORTANT: By default, the examples above will not restart automatically. You probably want to set a restart policy when you start petfeedd using docker. Otherwise, your cats will likely be very angry with you.
So, a complete example of running petfeedd using Docker would be something like:
$ docker run -d --restart always --privileged -v /etc/localtime:/etc/localtime -v /opt/petfeedd.db:/petfeedd/petfeedd.db -v /etc/petfeedd.conf:/petfeedd/petfeedd.conf -p 0.0.0.0:8080:8080 -p 0.0.0.0:11211:11211 peckrob/petfeedd-arm32v7
Once the command gets that large, you may consider using docker-compose
for
better reproducability.
If you haven't already installed docker-compose
you can do so with:
$ sudo apt update
$ sudo apt install -y python python-pip
$ sudo pip install docker-compose
Here is an example docker-compose.yml
file representing the above command.
version: '3'
services:
petfeedd:
privileged: true
image: peckrob/petfeedd-arm32v7
restart: always
volumes:
- /etc/localtime:/etc/localtime
- /opt/petfeedd.db:/petfeedd/petfeedd.db
- /etc/petfeedd.conf:/petfeedd/petfeedd.conf
ports:
- 0.0.0.0:8080:8080
- 0.0.0.0:11211:11211
Now you can just run:
$ docker-compose up -d
Simply docker pull peckrob/petfeedd-arm32v7
and restart the container.
While the Docker container is the fastest and most foolproof way to get going, you can also install from source directly onto the Raspberry Pi. This is also useful if you want to make changes to the source code.
-
apt-get install python3 python3-gpio python3-pip git
-
pip3 install pipenv
-
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - && sudo apt-get install -y nodejs
-
Clone the Repository. cd to the directory you cloned it to.
-
pipenv install
-
npm install
-
./node_modules/.bin/gulp
-
cp petfeedd.conf.example petfeedd.conf
-
Edit
petfeedd.conf
to your liking. -
useradd -d /path/to/your/checkout -G gpio petfeedd
-
cp init/systemd/petfeedd.service /etc/systemd/system
-
systemctl daemon-reload
-
systemctl start petfeedd
Be patient, it can take some time to start up. On my Raspberry Pi 3 Model B
version 1.2, it takes about 10 seconds. You can tail -f /var/log/syslog
for
when it is up and operational. Then you should be able to open a Browser and
configure your feeds.
petfeedd exposes a web API that can be used to build third-party clients. The API is REST/JSON. The web interface in fact uses the API.
GET /api/events
Will return a list of the 50 most recent feed events.
GET|POST /api/feeds
Sending GET will get all the scheduled feeds. Sending POST will create a new feed. Posting a new feed accepts the following as a JSON object in the body:
time
- "HH:MM:SS" string of the time of the feed, in 24 hour time.name
- A friendly name for the feed ("Breakfast", "Lunch", etc).size
- The size of the feed. This is a multiplier of the configsevo_feed_time
for how long it will run the servo.last_feed
- To reset or change the last feed time.feed_count
- To reset or change the feed count.
GET|POST|DELETE /api/feeds/<int>
Sending GET will get details about a specific feed. Sending POST will update the feed. Sending DELETE will delete the feed. Posting an updated feed accepts the same parameters as posting a new feed.
POST /api/feed
Will trigger an on-demand feed.
POST /api/pause
Pauses all feeding activity.
POST /api/start
Resumes feeding activity after a pause.
GET /api/status
Returns some information about the feeder.
petfeedd implements a simple auto-discovery mechanism to allow you to find
feeders on your network. Send a UDP broadcast packet to port 11213 containing
petfeedd
, and all the feeders on your network should respond with information
about themselves. This is useful for writing clients.
Patches are always welcome if you have some cool functionality you would like to add. To make things a little bit easier for development, there are some things that you should know.
You can run petfeedd locally. It will detect that it is not running on a Raspberry Pi and imitate a feed. PIGPIO is also included as a dev dependency so you should be able to use remote GPIO as well. I have not tested this, but I have no reason to believe it would not work.
To run locally, follow steps 4-7 above, then run:
$ pipenv run python3 src/__main__.py
From a source code checkout, you can build your own Docker images as well. In order to keep the Docker images as small as possible and reduce the build times, we use a build pipeline to do as much work as possible. The build pipeline:
- Cleans the build directory.
- Copies the sources into the build directory.
- Builds the assets.
- Removes everything that is not needed in the Docker image.
- Builds the Docker images.
- Cleans the build directory.
There is a gulp command to make it easy:
$ gulp build --image=<your image name> [--tag=latest] [--arch=<arch>]
If you don't pass an --arch
argument, it will build all architectures. Be
aware that this will take considerable time (it takes about 20 minutes to build
each ARM arch image on my 2018 MacBook Pro). For arch, you can pass any of the
supported architectures (that have a matching Dockerfile.<arch>
).
Rob Peck
GPLv3