Project tutorial
Pet Center - Feed and Entertain Your Pet

Pet Center - Feed and Entertain Your Pet © CC BY-NC

A simple and effective Alexa-based system to provide food and fun to your dog or cat.

  • 2,561 views
  • 0 comments
  • 8 respects

Components and supplies

Necessary tools and machines

Apps and online services

About this project

Intro

When I saw the Alexa and Arduino Smart Home challenge, I thought it was a great opportunity to build something to make people's life better. So I talked to my friends Diego and Elias an we went through a brainstorm to choose the project in which we would spend the next week.

There were lots of ideas of smart plant monitors, lamps and health related things, but we chose to stick with one the would make both people and pet lives a little better, and then Pet Center was born.

Hardware

The electronic parts (see main circuit schematic below) used aren't expensive and can be easily found.

ESP-01 is a bit tricky to program, and you will probably need an USB to Serial converter like FT232RL, and some 10K resistors. The text in orange indicates the corresponding FT232RL pins. These resistors are recommended for trouble-free programing, even though in the main schematic I've included just the ones required to make the chip run after code has been uploaded (GPIO0 and CH_PD).

Pet entertainment part is done using a camera pan/tilt module, two SG90 servos and a red laser diode. We warn you though, it's much more effective with cats than dogs!

As for the smart pet feeding system, we assembled it with PVC pipes. A handwound steel wire spring and an old microwave oven 120VAC motor do the heavy lifting: as the spring rotates with the motor shaft, food goes down the pipe and reaches the bowl.

Software

This part was the most difficult, but we ended up developing the endpoint in Python with Flask-Ask. The endpoint had to be always ready to provide a response, and there are many ways to achieve this, but our choice was Google Cloud due to their always free virtual machine instance. We also used localtunnel.me to get a public https url. Code is available below too.

After we got a working endpoint, creating an Alexa skill with the new Skills Kit Console was a nice experience, and no coding was required.

A simple VUI was designed :

Alexa, upon user command, makes a request to our endpoint, which provides the correct reply to the user (through Alexa) and publishes a MQTT message to the public broker iot.eclipse.org under petcenter topic.

ESP-01 is subscribed to this topic under the same broker and relays the message to Arduino Nano, which activates either the entertainment servos or the food serving mechanism, depending on the user request.

See it in action!

That pretty dog is called Belinha!

Showcase of all skill options

Code

ESP8266 MQTT to Serial BridgeArduino
Connects to remote MQTT server, subscribes to a topic and delivers every message to Arduino board through Serial port
//#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

//Enable/disable debug messages
#define DEBUG false


// Update these with values suitable for your network.
const char* ssid = "SSID";
const char* password = "PASS";
const char* mqtt_server = "iot.eclipse.org";
const int mqtt_port = 1883;

//topic to subscribe
const char* inTopic = "petcenter"; 
//topic to publish
const char* outTopic = "petcenter";

//Serial baud rate
const int baud = 115200;

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  if (DEBUG) Serial.println();
  if (DEBUG) Serial.print("Connecting to ");
  if (DEBUG) Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    if (DEBUG) Serial.print(".");
  }

  if (DEBUG) Serial.println("");
  if (DEBUG) Serial.println("WiFi connected");
  if (DEBUG) Serial.println("IP address: ");
  if (DEBUG) Serial.println(WiFi.localIP());
}

//Will be called once a message is received
void callback(char* topic, byte* payload, unsigned int length) {
  if (DEBUG) Serial.print("Message arrived [");
  if (DEBUG) Serial.print(topic);
  if (DEBUG) Serial.print("] ");
  for (int i = 0; i < length; i++) {
     Serial.print((char)payload[i]);
  }
  Serial.println();

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    if (DEBUG) Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client")) {
      if (DEBUG) Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish(outTopic, "hello world");
      // ... and resubscribe
      client.subscribe(inTopic);
    } else {
      if (DEBUG) Serial.print("failed, rc=");
      if (DEBUG) Serial.print(client.state());
      if (DEBUG) Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(baud);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
}

//Not used, will send hello world every 2 secs
void sendTestMsg(){
  long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;
    ++value;
    snprintf (msg, 75, "hello world #%ld", value);
    if (DEBUG) Serial.print("Publish message: ");
    if (DEBUG) Serial.println(msg);
    client.publish(outTopic, msg);
  }
}

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

}
petcenter-arduino-nano.inoArduino
Arduino code for Arduino Nano. Controls the servo, laser diode and pet feeding relay
#include <Arduino.h>
#include <Servo.h>
#include <ArduinoJson.h>

Servo servoH;
Servo servoV;

StaticJsonBuffer<200> jsonBuffer;

const int laserPin = 7;
const int relayPin = 4; // relay is active low

//Servo limits
const int hLim[] = {70,150};
const int vLim[] = {20,70};

//Init servo pos to middle
int posH = (hLim[1] + hLim[0])/2;
int posV = (vLim[1] + vLim[0])/2;

//Food motor ON time 
const unsigned long FOOD_DURATION = 35000;

bool shouldServeFood = false;
unsigned long lastFoodTime = 0;


void goTo(int target,Servo* servo, int* current){
//Slowly go to target position
while(*current>target){
    *current-=5;
    if(*current<target) *current = target;
    servo->write(*current);
    delay(75);
}
while(*current<target){
    *current+=5;
    if(*current>target) *current = target;
    servo->write(*current);
    delay(75);
}

}

void randomMotion(){
  //Randomly move both servos
    digitalWrite(laserPin,HIGH);

    for(int i=0;i<6;i++){
        goTo(random(hLim[0],hLim[1]),&servoH,&posH);
        delay(1000);
        goTo(random(vLim[0],vLim[1]),&servoV,&posV);
        delay(1000);
    }
    digitalWrite(laserPin,LOW);
}



void setup() {
    Serial.begin(115200);

    servoH.attach(9);
    servoV.attach(10);

    pinMode(laserPin,OUTPUT);
    pinMode(relayPin,OUTPUT);

    digitalWrite(laserPin,LOW);
    digitalWrite(relayPin,HIGH);

    servoH.write(posH);
    servoV.write(posV);

}

void manageFood(){
  //Keep food motor ON for the specified time, then turn it OFF
  
    if(millis()-lastFoodTime>FOOD_DURATION)
        shouldServeFood = false;
    
    if(shouldServeFood)
        digitalWrite(relayPin,LOW);
    else
        digitalWrite(relayPin,HIGH);
}

void loop() {

    manageFood();
    
    if(Serial.available()<4)
        return;

    JsonObject& root = jsonBuffer.parse(Serial);
    String cmd = root["cmd"];

    if(cmd=="feed"){
        shouldServeFood = true;
        lastFoodTime = millis();
    }
    else if(cmd=="play"){
        randomMotion();
    }
    else if(cmd=="blink"){
        digitalWrite(laserPin,HIGH);
        delay(1000);
        digitalWrite(laserPin,LOW);
    }

}
petcenter.pyPython
Python 3 code for our endpoint, you will need either ngrok or localtunnel to make it publicy available to Alexa.
Don't forget to put the templates.yaml file in the same folder as this.
from flask import Flask, render_template
from flask_ask import Ask, statement, question, session 
import requests
import json
import paho.mqtt.client as mqtt 

app = Flask(__name__)
ask = Ask(app,'/')

mqtt_broker_host = 'iot.eclipse.org' #"127.0.0.1"
mqtt_broker_port = 1883
mqtt_keepalive_secs = 60

mqtt_default_topic = 'petcenter'

# The callback for when the client receives a CONNACK response from the mqtt server. 
def on_connect(client, userdata, flags, rc): 
	print("Connected with result code "+str(rc)+'\n') 

def quick_pub(msg,topic):
	#client = mqtt.Client(transport="websockets") 
	client = mqtt.Client()
	client.on_connect = on_connect 
	client.connect(mqtt_broker_host, mqtt_broker_port, mqtt_keepalive_secs) 
	client.publish(topic,msg,qos=0,retain=False) 
	client.disconnect() 

@ask.launch 
def petcenter_launch(): 
   welcome_msg = render_template("welcome") 
   return question(welcome_msg).reprompt(welcome_msg)


@ask.intent("feed") 
def petcenter_feed(pet_type):
	if pet_type == None:
		pet_type = "pet"
	print("Feeding a : " + str(pet_type) +' right now \n')
	quick_pub('{\'cmd\':\'feed\'}',mqtt_default_topic) 
	msg = render_template("feed_response") 
	return statement(msg) 
    

@ask.intent("play")
def petcenter_play(pet_type):
	if pet_type == None:
		pet_type = "pet"
	print("Entertaining a : " + str(pet_type) +" right now \n")
	quick_pub('{\'cmd\':\'play\'}',mqtt_default_topic)
	msg = render_template("play_response", pet_type = pet_type)
	return statement(msg) 


@ask.intent('AMAZON.HelpIntent')
def help():
    help_text = render_template('help')
    return question(help_text).reprompt(help_text)


@ask.intent('AMAZON.StopIntent')
def stop():
    bye_text = render_template('bye')
    return statement(bye_text)


@ask.intent('AMAZON.CancelIntent')
def cancel():
    bye_text = render_template('bye')
    return statement(bye_text)


@ask.session_ended
def session_ended():
    return "{}", 200


if __name__ == "__main__": 
    app.run(debug=True) #default is localhost, port is 5000
templates.yamlYAML
Response templates for Alexa skill endpoint. Put this in the same folder as petcenter.py, and don't rename it.
welcome: Welcome to Pet Center ! What would you like to do ?
feed_response: Doing it right now !
play_response: I'll give your {{pet_type}} a good time !
bye: Goodbye
help: You can ask pet center feed my dog, or pet center play with my kitty or, you can say exit. What can I help you with?

Schematics

Main circuit
View of the main circuit. The AC motor is the pet feeding motor
Pet center bb kafgtsyadf

Comments

Similar projects you might like

Rampiot - Cool Smart Lock

Project tutorial by Robinson Mesino

  • 3,697 views
  • 1 comment
  • 23 respects

IoT Pet Feeder

Project tutorial by circuito.io team

  • 45,540 views
  • 33 comments
  • 153 respects

Arduino-Powered Smart Light (Works with Amazon Echo)

Project tutorial by Tinker Project

  • 14,707 views
  • 7 comments
  • 29 respects

Alexa Powered Arduino Kitchen Assistant

Project tutorial by TheParticleGuy

  • 2,629 views
  • 1 comment
  • 11 respects

Herb Box Eco System

Project tutorial by Walter Heger

  • 37,047 views
  • 20 comments
  • 239 respects

Alexa Based Smart Home Monitoring

Project tutorial by Adithya TG

  • 16,662 views
  • 19 comments
  • 47 respects
Add projectSign up / Login