Alimentador de Mascotas Automatizado por Raspberry Pi

Por: Josue Soriano Publicado el: 2017-08-12 16:36:41, 49680

Hace poco termine un proyecto de automatizacion que encontre en la pagina de Instructables, sin embargo la documentacion sobre el mismo es muy pobre en cuanto a la parte de la configuracion del sistema operativo en la Raspberry Pi y por el paso de las actualizaciones de algunas librerias ha quedado un poco obsoletas.

Explicando un poco el objetico de este proyecto, cosiste en hacer un dispositivo que me permita alimentar a mis mascotas de manera remota utilizando un correo electronico de GMail. El alimentador automatizado me permite consultar por medio de un correo electronico con el Subject: Cuando, este me contestara el correo un mensaje que indica cuando sera la proxima alimentacion adjuntando una foto del plato de comida para ver si ya esta o no vacio y tambien me permite enviar un e-mail con el Subject: Alimentar lo cual, si ya se cumplio un tiempo de 8 horas antes de la ultima alimentacion, comenzara a dispensar la comida; una vez terminada la alimentacion automatica me contestara el correo indicando que se ha dispensado correctamente la comida adjuntando una foto del plato de comida para corroborar que en efecto se haya llenado.

Se necesita armar un pequeño circuito que activa un Motor de Alto torque, y como mis conocimientos de electronica son muy pero muy escasos me tuve que pasar un par de dias aprendiendo las cosas basicas, asi que les recomiendo que vean los canales de Youtube de TerrazoCultor y sobre todo vean los videos de electornica basica de Charly Labs

El Script de automatizacion original esta escrito en Python, nunca habia usado este lenguaje de programacion pero la verdad no es tan diferente de los demas, lo he modificado un poco para que se adapte mejor a las nuevas librerias de Python y el proceso de automatizacion junto con las configuraciones del sistema operativo permiten parametrizar lo siguiente:

  • Interaccion por medio de comandos enviados a un correo electronico que permita el acceso a IMAP (Gmail)
  • Permite hacer un seguimiento de estado de la comida dispensada.
  • Controla cuanta comida se va a dispensar
  • Dispone de botones que permite hacer la alimentacion de manera manual.
  • No permite la sobrealimentacion deshabilitando la alimentacion en intervalos de 8 Horas.
  • Tiene una pantalle LCD de estatus que muestra los datos como la fecha y hora tiempo regresivo para la sisguiente aliemtacion, SSID al que esta conectado al WiFi y la direccion IP del equipo.
  • Opcional: Muestra algunos Chistes Random de Chuck Norris y/o trivias de Numeros utilizando un par de APIS publicas (Ingenioso por parte del autor original).
  • El Sistema es inmune a reinicios por cortes de electricidad ya que guarda un archivo de estado.

Materiales Utilizados

Todos los materiales anteriores a excepcion de los ultimos dos no se pueden conseguir localmente (o por lo menos no sabia donde conseguirlos), sin embargo la varilla y el acoplador probablemente se encuntren en algun taller de soldadura pero al ser la primera vez que hago algo asi, no tenia idea de como debia ser para que se acoplara al motor asi que lo pedi a la pagina de los links descritos anteriomente; acontinuacion los materiales que pude comprar en tiendas locales en San Pedro Sula:

  • Una caja de madera, yo utilice una de 20.3 cm ancho × 26.7 cm de alto x 13cm de profundidad. la caja tiene una puerta que abre hacia la derecha con un agujero de 10cm x 4cm para colocar la pantalla LCD (Ebanisteria local)
  • 3 botones (Comercial Lino)
  • 1 Protoboard pequeña (Comercial Lino)
  • 1 LED de 3.3 Voltios (No importa el color pero por el voltaje suelen ser Rojos) (Comercial Lino)
  • 1 transistor NPN PN2222 (Comercial Lino)
  • 1 Resistencia de 270 Ω (Comercial Lino)
  • 1 Resistencia de 10 KΩ (Comercial Lino)
  • 1 Potenciometro de 10 KΩ (Comercial Lino)
  • 1 Diodo IN4003 (Puede funcionar un IN4001 o IN4004) (Comercial Lino)
  • 1 adaprador de 12V 3A (Sycom)
  • 1 adaptador de 5V 2A (Sycom)
  • 4 tornillos con tuerca de mariposa de 1.5 pulgadas a 2 pulgadas (depende del grosor de la madera usada, son para fijar el bracket del motor a la caja de madera)
  • Cables Jumper hebras de diversos colores (Comercial Lino)
  • 1 tubo plegable o un lance de PVC de 4Pulg, este depende de la altura a la que estara colocada la caja de madera. (La Mundial)
  • un codo de PVC que se acople al lance anterior. (La Mundial)
  • 3 abrazaderas para tuberias de carro (La Mundial)
  • 4 Pies de Cable UTP (necesitamos los pares trenzados para hacer las conexiones) (Network Place o Sycom)
  • 1 WebCam USB, no es necesario que sea de alta resolucion. Yo encontre una agiler AGI-4186 en Caribecom que tiene leds que hacen la funcion extra de iluminar el plato.

Alguinos materiales micelaneos que se pueden conseguir en ferreterias o posiblemente ya tengamos:

  • Tape Industrial
  • Cautin
  • Estaño
  • Taladro
  • Broca 5/16
  • Tornillos S8 con expansores

Armando la estructura

La idea principal es sustituir la manija dispensadora que viene en el ZEVRO por la varilla D que luego se conectara al Motor por medio del Acoplador. El dispensador se sujetara de la caja de madera y la caja de madera a la Pared. Como no se mucho de electrónica no utilicé ninguna placa de baquelita para montar el circuito así que use la protoboard para poder poner todos los componentes así que en el fondo de la caja va sujeta con tornillos la Rapberry Pi y la protoboard la cual ya tenía un adhesivo en la parte de atrás así que solo fue de pegarla.  La caja debe de tener tres botones los cuales tendrán la función de Reiniciar el temporizador, activar el alimentador y el último será un paso directo para activar el motor sin pasar por el circuito. El motor se sujetara dentro de la caja por medio del braket por lo que, de la caja, solo sobresaldrá la varilla D que se conecta al dispensador, en la parte de abajo de la caja fije y ajuste la webcam para que en cada correo de consulta y confirmacion me envie una foto de como esta el plato, esto para no sobre alimentar en caso de que no se hayan terminado la ultima tanda de comida.

De la parte inferior del dispensador se colocara el tubo  que bajara hasta el plato y en la base se colocara el codo de PVC, yo coloque un poco de Tape Industrial en la salida para minimizar la velocidad del flujo de comida e hice una base dispensadora para evitar que la comida salga disparada por todos lados. Para fijar el tubo a la pared utilice abrazaderas metálicas que fije a la pared con los tornillos para taco S8.

En la puerta de la caja sujete la placa de la pantalla LCD y utilice los pares trenzados del cable UTP para llevarlos directamente a la Raspberry, en el otro extremo de los cables empalme las puntas hembras de los jumpers para hacer más fácil la conexión en los puertos GPIO de la Raspberry. Este sería el diagrama de circuitos. Voy a tratar de explicarlo con lo poco lo que logre captar de Electrónica.

El motor se conecta directamente al polo positivo del transformador de 12 voltios pero para que la corriente fluya debe pasar por el circuito en el polo neutro del motor, para ello se utiliza el transistor N2222. Los transistores tienen normalmente 3 patitas las cuales corresponden a un colector, una base y un emisor, dependiendo del modelo del transistor la ubicación de estas patitas pueden variar; este transistor hace la función de Switch aquí es donde conectamos el polo neutro del motor al colector del transistor, el pin #19 de la rapberry se conecta a la base por medio de una resistencia de 270Ω y el emisor se conecta a la terminal neutra del transformador de 12V junto con uno de los polos Tierra de la raspberry; el transistor dejara fluir la corriente entre colector y emisor siempre y cuando la base se estimule con suficiente voltaje; mas adelante programaremos las rapberry para que según ciertas ordenes el puerto 19 emitirá 3.3 voltios, lo suficiente para que el circuito continúe y active el motor.

Para la pantalla LCD se utiliza otra parte de la protobard en un circuito diferente donde conecte el potenciómetro  de 10KΩ el cual recula el contraste del texto que aparece en la pantalla LCD, así que si no aparece nada en la pantalla es porque probablemente el potenciómetro este totalmente cerrado; en  mi caso yo lo deje totalmente abierto para que se visualice mejor el texto. Al final las conexiones en la protoboard quedarían de la siguiente manera.

Configuración de la Raspberry

Para configurar la rapberry utilice la versión Lite del Rapbian (no necesitamos la carcasa grafica) y aplique la configuración básica que muestra el raspbian una vez que se instala o utilizando el comando raspi-config: expandi el espacio al 100% y habilite el SSH pero sobre todo lo mas importante es cambiar la contraseña y el nombre de usuario al usuario pi que viene por defecto (De lo contrario, como me paso a mi, pueden sufrir un ataque por el puerto 22 si tienen una IP publica direccionada a la raspberry). Aparte de eso la configuracion para que se conecte automaticamente a mi red WiFi (Suponiendo que me red se llama "BlogSoriano" y mi password es "$eguridad123!") generamos y guardamos la clave en el archivo de conexiones Wireless con el siguiente comando:

$ sudo wpa_passphrase "BlogSoriano" "$eguridad123!" | sudo tee -a /etc/wpa_supplicant/wpa_supplicant.conf > /dev/null

lo siguiente es actualizar e instalar el sistema de instalacion de python "pip" para ello vamos a loguearnos como root, actualizar e instalar los paquetes necesarios:

$ sudo -i
$ apt-get update
$ apt-get install build-essential python-dev python-smbus python-pip

Con esto ya tenemos acceso a la libreria de clases de python, para el script que vamos a usar se necesita instala lo siguiente:

$ pip install IMAPClient RPi.GPIO Adafruit-CharLCD httplib2 html2text netifaces wireless

Una vez terminada la instalacion de dependencias vamos a escribir el siguiente script, yo lo guarde en la ruta /opt/petfeeder.py el archivo lo pueden crear mediante el comando nano /opt/petfeeder.py  y dentro de este archivo pegamos el siguiente codigo, aclaro que este codigo no lo escribi yo ya que nunca habia programado en Python, unicamene lo modifique para que funcione con las nuevas librerias y con la pantalla LCD de 20x4; tambien inclui una funcion para leer tweets random desde algunas cuentas que yo sigo desde una API que programe en PHP la cual compartire mas tarde:

###########################################################################################
# petfeeder.py v 2.0
#
# Author: Krish Sivakumar
# Modificador: Josue Soriano
# Creado en Dic. 2015
# Actualizado Jul 2017
#
# Program to automate on-demand pet feeding through the internet
# Uses Raspberry Pi as a controller
#
# Distributed under Creative Commons Attribution-NonCommercial-Sharealike licensing
# https://creativecommons.org/licenses/by-nc-sa/3.0/us/
#
############################################################################################

from imapclient import IMAPClient, SEEN
import time
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os
import sys
import RPi.GPIO as GPIO
from Adafruit_CharLCD import Adafruit_CharLCD
import httplib2
import json
import html2text
import cv2
import netifaces as ni
from wireless import Wireless

DEBUG = False
MOTORON = True
CHUCKNORRIS = True #activa para que adjunte un chiste de Chuck Norris en ingles en los correos
NUMBERTRIVIA = True #active para que mande dentro de los correos una trivia de un numero aleatorio.
TWEETS = False #implementacion propia para adjuntar Tweets Random desde un API personal.
TWEETSAPI = "" #URL del API que me retorna tweets de cuentas que sigo.

# Here is our logfile
LOGFILE = "/tmp/petfeeder.log"

# Variables for checking email
GMAILHOSTNAME = 'imap.gmail.com' # Insert your mailserver here - Gmail uses 'imap.gmail.com'
MAILBOX = 'Inbox' # Insert the name of your mailbox. Gmail uses 'Inbox'
GMAILUSER = '@gmail.com'# Insert your email username
GMAILPASSWD = 'mipassword'# Insert your email password
EMAILNOTIFICATIONS = 'correopersonal@gmail.com' #correo al que llegaran las notificaciones
NEWMAIL_OFFSET = 0
lastEmailCheck = time.time()
MAILCHECKDELAY = 30  # Don't check email too often since Gmail will complain

# GPIO pins for feeder control
MOTORCONTROLPIN = 19
FEEDBUTTONPIN = 6
RESETBUTTONPIN = 13

# GPIO pins for 20x4 HD44780
lcd_rs = 27
lcd_en = 22
lcd_d4 = 25
lcd_d5 = 24
lcd_d6 = 23
lcd_d7 = 18
lcd_bl = 4

lcd_cols = 20
lcd_rows = 4


# Variables for feeding information
readyToFeed = False # not used now but for future use
feedInterval = 28800 # This translates to 8 hours in seconds
FEEDFILE="/tmp/lastfeed.log"
cupsToFeed = 1.5
motorTime = cupsToFeed * 27 # It takes 27 seconds of motor turning (~1.75 rotations) to get 1 cup of feed

PHOTOFILE = '/tmp/foodstatus.jpg'

# Function that gets Chuck Norris jokes from the internet. It uses an HTTP GET and then a JSON parser
def getChuckNorrisQuote():
    # The database where the jokes are stored
    ICNDB="http://api.icndb.com/jokes/random"
    # Doing a HTTP request to get the response (resp) and content (content)
    resp, content = httplib2.Http().request(ICNDB)
    # The content is in the following JSON format and needs to be parsed
    # {u'type': u'success', u'value' : {u'joke': 'Text of the joke', u'id': 238, u'categories': []}}
    parsed_content = json.loads(content)
    joke = "\n\n** Chiste Random de Chuck Norris **:\n" + html2text.html2text(parsed_content['value']['joke'])
    return joke
    

# Function that gets a number trivia from the internet. It uses an HTTP GET and then a JSON parser
def getNumberTrivia():
    # The database where the trivia are stored
    NUMDB="http://numbersapi.com/random/trivia?json"
    # Doing a HTTP request to get the response (resp) and content (content)
    resp, content = httplib2.Http().request(NUMDB)
    # The content is in the following JSON format and needs to be parsed
    # {u'text': u'Text of trivia', u'type' : u'trivia, u'number': , u'found': True}
    parsed_content = json.loads(content)
    trivia = "\n\n** Curiosidad del Numero " + str(parsed_content['number']) + " **\n"
    trivia = trivia + parsed_content['text']
    return trivia

def getTweets():
    global TWEETSAPI
    # Doing a HTTP request to get the response (resp) and content (content)
    resp, content = httplib2.Http().request(TWEETSAPI)
    # The content is in the following JSON format and needs to be parsed
    # {u'text': u'Text of trivia', u'type' : u'trivia, u'number': , u'found': True}
    parsed_content = json.loads(content)

    tweets = "\n\n*** No Hay Tweets Disponibles ***"
    if parsed_content['usuario'] is not None:    
        tweets = "\n\n*** Tweet de Random de " + html2text.html2text(parsed_content['usuario']) + "\n"
        tweets = tweets + html2text.html2text(parsed_content['tweet'])
        if parsed_content['mediaUrl'] is not None:
            tweets = tweets + "\n" + html2text.html2text(parsed_content['mediaUrl'])
	
    return tweets    

# Function to check email
def checkmail():
    global lastEmailCheck
    global lastFeed
    global feedInterval
    
    if (time.time() > (lastEmailCheck + MAILCHECKDELAY)):  # Make sure that that atleast MAILCHECKDELAY time has passed
        lastEmailCheck = time.time()
        server = IMAPClient(GMAILHOSTNAME, use_uid=True, ssl=True)  # Create the server class from IMAPClient with HOSTNAME mail server
        server.login(GMAILUSER, GMAILPASSWD)
        server.select_folder(MAILBOX)
        
        # See if there are any messages with subject "When" that are unread
        whenMessages = server.search([u'UNSEEN', u'SUBJECT', u'Cuando'])

        # Respond to the when messages
        if whenMessages:
            for msg in whenMessages:
                msginfo = server.fetch([msg], ['BODY[HEADER.FIELDS (FROM)]'])
                fromAddress = str(msginfo[msg].get('BODY[HEADER.FIELDS (FROM)]')).split('<')[1].split('>')[0]
                msgBody = "La ultima alimentacion se realizo el " + time.strftime("%b %d at %I:%M %P", time.localtime(lastFeed))

                if (time.time() - lastFeed) > feedInterval:
                    msgBody = msgBody + "\nListo para alimentar ahorita!"
                else:
                    msgBody = msgBody + "\nLa siguiente alimentacion comenzara el " + time.strftime("%b %d at %I:%M %P", time.localtime(lastFeed + feedInterval))

                if NUMBERTRIVIA:
                    msgBody = msgBody + getNumberTrivia()

                if CHUCKNORRIS:
                    msgBody = msgBody + getChuckNorrisQuote()

                if TWEETS:
                    msgBody = msgBody + getTweets()

                getPhoto()                                
                sendemail(fromAddress, "Gracias por la consulta de Alimentacion", msgBody, PHOTOFILE)
                server.add_flags(whenMessages, [SEEN])


        # See if there are any messages with subject "Feed" that are unread
        feedMessages = server.search([u'UNSEEN', u'SUBJECT', u'Alimentar'])
        
        # Respond to the feed messages and then exit
        if feedMessages:
            for msg in feedMessages:
                msginfo = server.fetch([msg], ['BODY[HEADER.FIELDS (FROM)]'])
                fromAddress = str(msginfo[msg].get('BODY[HEADER.FIELDS (FROM)]')).split('<')[1].split('>')[0]

                msgBody = "La ultima alimentacion se realizo el " + time.strftime("%b %d at %I:%M %P", time.localtime(lastFeed))
                if (time.time() - lastFeed) > feedInterval:
                    msgBody = msgBody + "\nLa alimentacion comenzara en breves momentos"
                else:
                    msgBody = msgBody + "\nLa proxima alimentacion se realizara el " + time.strftime("%b %d at %I:%M %P", time.localtime(lastFeed + feedInterval))

                if NUMBERTRIVIA:
                    msgBody = msgBody + getNumberTrivia()

                if CHUCKNORRIS:
                    msgBody = msgBody + getChuckNorrisQuote()

                if TWEETS:
                    msgBody = msgBody + getTweets()

                                                
                sendemail(fromAddress, "Gracias por tu solicitud de alimentacion", msgBody)

                server.add_flags(feedMessages, [SEEN])
            return True

    return False


def sendemail(to, subject, text, attach=None):
    msg = MIMEMultipart()
    msg['From'] = GMAILUSER
    msg['To'] = to
    msg['Subject'] = subject
    msg.attach(MIMEText(text.encode('utf-8'), 'plain', 'utf-8'))
    if attach:
        part = MIMEBase('application', 'octet-stream')
        part.set_payload(open(attach, 'rb').read())
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(attach))
        msg.attach(part)
    mailServer = smtplib.SMTP("smtp.gmail.com", 587)
    mailServer.ehlo()
    mailServer.starttls()
    mailServer.ehlo()
    mailServer.login(GMAILUSER, GMAILPASSWD)
    mailServer.sendmail(GMAILUSER, to, msg.as_string())
    mailServer.close()



def buttonpressed(PIN):
    # Check if the button is pressed
    global GPIO
    
    # Cheap (sleep) way of controlling bounces / rapid presses
    time.sleep(0.2)
    button_state = GPIO.input(PIN)
    if button_state == False:
        return True
    else:
        return False


def remotefeedrequest():
    # At this time we are only checking for email
    # Other mechanisms for input (e.g. web interface or iOS App) is a TO-DO
    return checkmail()


def printlcd(row, col, LCDmesg):
    # Set the row and column for the LCD and print the message
    global logFile
    global lcd
    
    lcd.set_cursor(row, col)
    
    lcd.message(LCDmesg)

    lcd.set_cursor(0,2)
    lcd.message("Wifi: " + getSSID())
    lcd.set_cursor(0,3)
    lcd.message("IP: " + getIP())

	


def feednow():
    # Run the motor for motorTime, messages in the LCD during the feeeding
    global GPIO
    global MOTORCONTROLPIN
    global motorTime
    global lastFeed
    global GMAILUSER
    global lastFeed

    lcd.clear()
    printlcd(0,0,"Alimentando.....")
    #print "Alimentando...."
    if MOTORON:
        GPIO.output(MOTORCONTROLPIN, True)
        time.sleep(motorTime)
        GPIO.output(MOTORCONTROLPIN, False)
        lastFeed = time.time()
        saveLastFeed()

        printlcd(0,1, "\nAlimentacion Terminada!")
	msgBody = "Alimentacion terminada exitosamente!"
	if NUMBERTRIVIA:
            msgBody = msgBody + getNumberTrivia()

        if CHUCKNORRIS:
            msgBody = msgBody + getChuckNorrisQuote()

        if TWEETS:
            msgBody = msgBody + getTweets()

        getPhoto()
        sendemail(EMAILNOTIFICATIONS, "Alimentacion exitosa el " + time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(lastFeed)), msgBody, PHOTOFILE)
        time.sleep(2)
    return time.time()

def saveLastFeed():
    global FEEDFILE
    global lastFeed
    with open(FEEDFILE, 'w') as feedFile:
        feedFile.write(str(lastFeed))
    feedFile.close()

def getPhoto():
    global PHOTOFILE
    camera_port = 0 
    camera = cv2.VideoCapture(camera_port) 
    time.sleep(0.1) 
    return_value, image = camera.read() 
    cv2.imwrite(PHOTOFILE, image)
    del(camera)

def getIP():
    global ni
    try:
        ni.ifaddresses('wlan0')
        ip = ni.ifaddresses('wlan0')[ni.AF_INET][0]['addr']
    except:
        ip = "0.0.0.0"

    return ip
        
def getSSID():
    try:
        wireless = Wireless()
        ssid = wireless.current()
    except:
        ssid = "Ninguno"

    return ssid


# This is is the main program, essentially runs in a continuous loop looking for button press or remote request
try:
    print "Iniciando Servicio de Alimentacion"
    #### Begin initializations #########################
    ####################################################
    
    # Initialize the logfile
    logFile = open(LOGFILE, 'a')

    # Initialize the LCD
    lcd = Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, lcd_cols, lcd_rows, lcd_bl)
    # lcd.begin(16,2)
    lcd.clear()
    lcd.show_cursor(False)
    

    # Initialize the GPIO system
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)

    # Initialize the pin for the motor control
    GPIO.setup(MOTORCONTROLPIN, GPIO.OUT)
    GPIO.output(MOTORCONTROLPIN, False)

    # Initialize the pin for the feed and reset buttons
    GPIO.setup(FEEDBUTTONPIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(RESETBUTTONPIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    
    # Initialize lastFeed
    if os.path.isfile(FEEDFILE):
        with open(FEEDFILE, 'r') as feedFile:
            lastFeed = float(feedFile.read())
        feedFile.close()
    else:
        lastFeed = time.time()
        saveLastFeed()
        

    #### End of initializations ########################
    ####################################################

    #### The main loop ####
    
    while True:
        try:
            #### If reset button pressed, then reset the counter
            if buttonpressed(RESETBUTTONPIN):
                lcd.clear()
      	        print "Reiniciando...  "
                printlcd(0,0, "Reiniciando...   ")
                time.sleep(2)
                lastFeed = time.time() - feedInterval + 5
                saveLastFeed()
        
            #### Check if we are ready to feed
            if (time.time() - lastFeed) > feedInterval:
                #lcd.clear()
                printlcd(0,0, time.strftime("%m/%d %I:%M:%S%P", time.localtime(time.time())))
                printlcd(0,1, "Listo para Alimentar")

                #### See if the button is pressed
                if buttonpressed(FEEDBUTTONPIN):
	            #print "Boton Presionado"
                    feednow()
            
                #### Check if remote feed request is available
                elif remotefeedrequest():
                    feednow()
                
            #### Since it is not time to feed yet, keep the countdown going
            else:
                timeToFeed = (lastFeed + feedInterval) - time.time()
                #lcd.clear()
                printlcd(0,0, time.strftime("%m/%d %I:%M:%S%P", time.localtime(time.time())))
                printlcd(0,1, 'Proxima: ' + time.strftime("%Hh %Mm %Ss", time.gmtime(timeToFeed)))
                checkmail()
                if buttonpressed(FEEDBUTTONPIN):
	  	    #print "Boton Presionado"
                    lcd.clear()
                    printlcd(0,0, "Ahora no, intenta el")
                    printlcd(0,1, time.strftime("%b/%d %H:%M", time.localtime(lastFeed + feedInterval)))
		    #print time.strftime("%b/%d %H:%M", time.localtime(lastFeed + feedInterval))
                    time.sleep(2)
            time.sleep(.6)
        except Exception as e:
            logError = time.strftime("%m/%d %I:%M:%S%P", time.localtime(time.time())) + " Error inesperado: " + str(e) + "\n"
            sendemail(EMAILNOTIFICATIONS, "Registro de error", logError)
            logFile.write(logError)

#### Cleaning up at the end
except KeyboardInterrupt:
    logFile.close()
    lcd.clear()
    GPIO.cleanup()

except SystemExit:
    logFile.close()
    lcd.clear()
    GPIO.cleanup()

Una vez que tengamos el Script hay que cambiar los valores de las variables con los correos electronicos que se requieran, yo les recomiendo que usen gmail por su facilidad de conexion por medio del protocolo IMAP, con eso solo quedaria guardar el archivo y salir (con Ctrl+o se guarda y ctrl+x se sale del editor nano), solo nos hace falta que sea a prueba de reinicios; el script por si ya guarda la ultima vez que se activo el sistema de alimentacion, por lo que solo debemos hacer que el script se ejecute cada vez que se inicie el sistema operativo, para ello encontre una solucion muy particular con un programa llamado supervisor, el cual se instala desde los repositorios del Debian:

$ apt-get install supervisor

y una vez instalado solamente necesitamos crear un archivo de configuracion en /etc/supervisor/conf.d/petfeeder.conf, al igual que el caso anterior lo podemos crear y guardar con nano, este archivo tendra lo siguiente:

[program:petfeederd]
directory=/opt
command=python petfeeder.py
autostart=true
autorestart=true

Una vez guardado el archivo podemos usar el comando supervisorctl [start|stop|restart] petfeederd, como en este caso el servicio no se ha iniciado lo ejecutamos con start:

$ supervisorctl start petfeederd

Y con esto ya deberia funcionar el sistema, la pantalla LCD deberia mostrar informacion de cuando deberia ser la siguiente alimentacion o si ya esta listo para alimentar deberia decirlo. Tambien debe mostrar el nombre de la Red inalambrica a la que se esta conectado y la direccion IP que se esta utilizando por si necesitamos conectarnos por medio de SSH, comparto un pequeño video que hice, me disculpo por la calidad del mismo, no soy muy bueno es este tema de los vlogs.

 

Si te Gusto compartelo:

Comentar

Debes ingresar para poder comentar, accede AQUI. Registrate AQUI

Comentarios