Paso 3: Escribir los programas de Python
Empecé la programación, centrándose en un sistema de pantalla táctil interactiva simple usando sobre todo Tkinter objetos para crear un python GUI. Todo el código se incluye tener un quiosco estilo photobooth. El código está incluido en un archivo zip en este instructable. Después de ejecutar esto durante varios días he tenido unos pequeños cambios que yo he rectificado en el archivo zip de subir y en estos ejemplos.
El proyecto consta de tres programas:
- christmas_motion.py - esto es lo que ponga en marcha cuando el PI comienza, monitorea el sensor de movimiento y cuando se detecta movimiento, comprueba si existe un archivo que sólo existe cuando se ejecuta el programa principal "christmas_wreath_2.0.py". Si el archivo existe no hace nada, si no es así entonces el programa de movimiento se inicia el programa principal "christmas_wreath_2.0.py"
- Principales acciones:
- Monitor de movimiento
- Inicio christmas_wreath_2.0.py
- Cerrar el protector de pantalla "feh"
- Principales acciones:
- christmas_wreath_2.0.py - este es el programa principal, que hace cuatro cosas:
- Pregunta al visitante a la puerta de su casa si quieren tomar una foto "Elfie"
- Coger / tomar fotos
- Imprimir
- Dejar de fumar
- christmas_nowprinting.py - se utiliza para mostrar un GIF animado de una impresora. Ya que la impresora es bluetooth el trabajo de impresión tarda unos dos minutos para completar. Después de ello, el archivo impide que el programa de movimiento dando inicio a un nuevo programa "Tomar Elfie" (christmas_wreat_2.0.py"se elimina y vuelve a nuestro proceso.
Código:
christmas_motion.py
import RPi.GPIO as GPIOimport time import os from subprocess import Popen import os.pathGPIO.setmode(GPIO.BCM) PIR_PIN = 7 GPIO.setup(PIR_PIN, GPIO.IN)adef MOTION(PIR_PIN): print "Motion Detected!" #try: # os.system("killall -9 feh") # Open a file in write mode if os.path.exists("/home/pi/Documents/pythonprograms/christmas_wreath_placeholder.txt"): logfile=open("motionlog.txt", "rw+") print "Name of the file: ", logfile.name str1 = time.strftime("%Y%m%d-%H%M%S") str2 = "\n" str3 = str1+str2 # Write a line at the end of the file. logfile.seek(0, 2) line = logfile.write( str3 ) # Close opend file logfile.close() else: proc = Popen(["python /home/pi/Documents/pythonprograms/christmas_wreath_2.0.py"], shell=True, stdin=None, stdout=None, stderr=None, close_fds=True) time.sleep(3) os.system("killall -9 feh") print "PIR Module Test (CTRL+C to exit)" time.sleep(10) print "Ready" proc = Popen(["python /home/pi/Documents/pythonprograms/christmas_wreath_2.0.py"], shell=True, stdin=None, stdout=None, stderr=None, close_fds=True)if os.path.exists("/home/pi/Documents/pythonprograms/christmas_wreath_placeholder.txt"): os.remove("/home/pi/Documents/pythonprograms/christmas_wreath_placeholder.txt")try: GPIO.add_event_detect(PIR_PIN, GPIO.RISING, callback=MOTION) while 1: time.sleep(100) except KeyboardInterrupt: print "Quit" GPIO.cleanup()
christmas_wreath_2.0.py
#!/usr/bin/env pythonimport osfrom time import sleep import tkFont from Tkinter import * import Tkinter as tk from ImageWin import Dib,HWND from PIL import Image from PIL import ImageTk from subprocess import Popen import shutil import os.pathimport time#from SimpleCV import Imageimport picameraclass App: def __init__(self, master): self.counter = 0 im = Image.open("/home/pi/Pictures/christmasbg1.jpg") resized = im.resize((340, 240),Image.ANTIALIAS) tkimage = ImageTk.PhotoImage(resized) myvar=Label(frame,image = tkimage,bg="black", text="", compound=tk.BOTTOM, font=btnFont, fg='white') myvar.image = tkimage myvar.grid(row=1,column=0,sticky=N+S+E+W) ## notice, don't use button.pack and button.grid interchangeably - grid forces buttons into the column/row locations you specify ## pack allows the tkinter system to determine what should work best self.button1 = Button(frame,relief=FLAT,bg="red",activebackground="white",foreground="silver", text="No Thanks,\n Merry Christmas", font=btnFont, command=self.quit_pressed) self.button1.grid(row=1,column=1,sticky=N+S+E+W) #self.button1.pack(fill=BOTH,expand=1) self.button2 = Button(frame,relief=FLAT,bg="green",activebackground="red",foreground="silver", text="Take 'Elfie'?", font=btnFont, command=self.pi_picture) self.button2.grid(row=0,column=0,sticky=N+S+E+W) #self.button2.pack(fill=BOTH,expand=1) #SHOW ELFIE BUTTON - BLANK UNTIL ELFIE TAKEN self.button4 = Button(frame,relief=FLAT,bg="green",activebackground="red",foreground="silver", font=btnFont, state=DISABLED, command=self.show_elfie) self.button4.grid(row=0,column=1,sticky=N+S+E+W) #self.button4.pack(fill=BOTH,expand=1) def show_elfie(self): im = Image.open("/home/pi/Documents/pythonprograms/imagetest2.jpg") resized = im.resize((340, 240),Image.ANTIALIAS) tkimage = ImageTk.PhotoImage(resized) myvar=Label(frame,image = tkimage,bg="red", text="Your Elfie Preview", compound=tk.BOTTOM, font=btnFont, fg='white') myvar.image = tkimage self.button4["text"] = "Print Elfie?\nClick 'Take Elfie' to re-take" myvar.grid(row=1,column=0,sticky=N+S+E+W) def create_window(self): self.counter += 1 t = Toplevel() center(t) t.title("Picture Here") msg = Message(t,text="Put Picture Here") msg.pack() t.wm_title("Window #%s" % self.counter) im = Image.open("/home/pi/Pictures/christmasbg1.jpg") #tkroot = Tk() tkimage = ImageTk.PhotoImage(im) frame = Frame(relief=FLAT, bg='green') frame.pack_propagate(0) frame.pack(fill=BOTH, expand=1) frame.rowconfigure((0,1),weight=1) frame.columnconfigure((0,1),weight=1) Label(frame,image=tkimage).pack() button = Button(frame,text="Dismiss", command=t.destroy) button.pack() def quit_pressed(self): proc = Popen(["feh -Y -x -q -D 5 -B black -F -Z -z -r /home/pi/Pictures"], shell=True, stdin=None, stdout=None, stderr=None, close_fds=True) sleep(2) os.remove("christmas_wreath_placeholder.txt") #os.system("feh -Y -x -q -D 5 -B black -F -Z -z -r /home/aaron/Pictures") quit() #This will kill the application itself, not the self frame. def pi_picture(self): with picamera.PiCamera() as camera: camera.resolution=(1920,1080) #camera.exposure_mode="backlight" #camera.awb_mode="shade" camera.start_preview() sleep(4) global filepath filepath="/home/pi/Documents/pythonprograms/wreathpics/" global filenamestring filenamestring=time.strftime("%Y%m%d-%H%M%S") global filext filext=".jpg" global filefullname filefullname=filepath+filenamestring+filext camera.capture(filefullname) camera.stop_preview() #sleep(2) im = Image.open(filefullname) resized = im.resize((340, 240),Image.ANTIALIAS) tkimage = ImageTk.PhotoImage(resized) myvar=Label(frame,image = tkimage,bg="red", text="Elfie Preview", compound=tk.BOTTOM, font=btnFont, fg='white') myvar.image = tkimage self.button2["text"] = "Re-Take Elfie?" self.button4["text"] = "Print Elfie?" self.button4["state"]= "normal" self.button4["command"] = self.print_elfie myvar.grid(row=1,column=0,sticky=N+S+E+W) def print_elfie(self): #setup print stuff destdir="/home/pi/Documents/pythonprograms/wreathpics/prints/" destpath=destdir+filenamestring+filext shutil.copy2(filefullname,destpath) obexftpstr="sudo obexftp -b 00:04:48:10:0B:21 --channel 1 -p " obexftpfull=obexftpstr+filefullname print obexftpfull proc = Popen([obexftpfull], shell=True, stdin=None, stdout=None, stderr=None, close_fds=True) proc = Popen(["python christmas_nowprinting.py"], shell=True, stdin=None, stdout=None, stderr=None, close_fds=True) sleep(1) #os.system("feh -Y -x -q -D 5 -B black -F -Z -z -r /home/aaron/Pictures") quit() #This will kill the application itself, not the self frame.class ImageView(Frame): def __init__(self,master,**options): Frame.__init__(self,master,**options) self.dib = None self.bind("",self._expose) def setimage(self,image): self.config(bg="") self.dib = Dib(image) self.event_generate("") def _expose(self,event): if self.dib: self.dib.expose(HWDN(self.winfo_id())) def center(win): """ centers a tkinter window :param win: the root or Toplevel window to center """ win.update_idletasks() width = win.winfo_width() frm_width = win.winfo_rootx() - win.winfo_x() win_width = width + 2 * frm_width height = win.winfo_height() titlebar_height = win.winfo_rooty() - win.winfo_y() win_height = height + titlebar_height + frm_width x = win.winfo_screenwidth() // 2 - win_width // 2 y = win.winfo_screenheight() // 2 - win_height // 2 win.geometry('{}x{}+{}+{}'.format(width, height, x, y)) win.deiconify()def close_after(): proc = Popen(["feh -Y -x -q -D 5 -B black -F -Z -z -r /home/pi/Pictures"], shell=True, stdin=None, stdout=None, stderr=None, close_fds=True) sleep(2) os.remove("christmas_wreath_placeholder.txt") #os.system("feh -Y -x -q -D 5 -B black -F -Z -z -r /home/aaron/Pictures") quit() #This will kill the application itself, not the self frame. #this is the main program root = Tk()w, h = root.winfo_screenwidth(), root.winfo_screenheight() # use the next line if you also want to get rid of the titlebar to run a full screen app root.overrideredirect(1)root.geometry("%dx%d+0+0" % (w, h)) root.config(bg="black",padx=10,pady=10) #root.rowconfigure((0,1),weight=1) #root.columnconfigure((0,1),weight=1)#put the frame here to make it globally available to the sub routines frame = Frame(relief=FLAT, bg='darkgreen', bd="0") frame.rowconfigure((0,1),weight=1) frame.columnconfigure((0,1),weight=1) frame.pack_propagate(0) frame.pack(fill=BOTH, expand=1) btnFont = tkFont.Font(family='Times',size=32,weight='bold')if not os.path.exists("christmas_wreath_placeholder.txt"): open("christmas_wreath_placeholder.txt","w")root.after(300000, close_after) #call quit after 5 minutes no matter whatapp = App(root) root.mainloop()#os.system("pkill -x feh")#exit()
christmas_nowprinting.py
from Tkinter import * from PIL import Image, ImageTk from subprocess import Popen import os.pathclass MyLabel(Label): def __init__(self, master, filename): im = Image.open(filename) seq = [] try: while 1: seq.append(im.copy()) im.seek(len(seq)) # skip to next frame except EOFError: pass # we're done try: self.delay = im.info['duration'] except KeyError: self.delay = 100 first = seq[0].convert('RGBA') self.frames = [ImageTk.PhotoImage(first)] Label.__init__(self, master, image=self.frames[0]) temp = seq[0] for image in seq[1:]: temp.paste(image) frame = temp.convert('RGBA') self.frames.append(ImageTk.PhotoImage(frame)) self.idx = 0 self.cancel = self.after(self.delay, self.play) def play(self): self.config(image=self.frames[self.idx]) self.idx += 1 if self.idx == len(self.frames): self.idx = 0 self.cancel = self.after(self.delay, self.play) root = Tk() w, h = root.winfo_screenwidth(), root.winfo_screenheight() root.overrideredirect(1) root.geometry("%dx%d+0+0" % (w, h)) root.config(bg="darkgreen",padx=10,pady=10) anim = MyLabel(root, "/home/pi/Documents/pythonprograms/nowprinting.gif") anim.pack()def stop_it(): anim.after_cancel(anim.cancel)#Button(root, text='stop', command=stop_it).pack() root.after(107000,lambda: os.remove("christmas_wreath_placeholder.txt")) root.after(109000,lambda: Popen(["feh -Y -x -q -D 5 -B black -F -Z -z -r /home/pi/Pictures"], shell=True, stdin=None, stdout=None, stderr=None, close_fds=True)) root.after(110000,lambda: root.destroy()) #destroy the widget after 20secondsroot.mainloop()
Conseguir la PI a AutoStart la Tkinter basado en Python app con la sesión de usuario
Que es un bocado, pero básicamente sólo se puede ejecutar este tkinter aplicación dependiente de python desde la línea de comandos en un entorno único de la consola, tienes que ser un x-Windows o LXDE, aka, un escritorio de Linux normal - no telnet o SSH ya que esta es una aplicación GUI. Para hacer esto en una frambuesa PI hay un archivo específico de autostart que edita que ejecuta aplicaciones de interfaz gráfica de usuario o GUI no tras el escritorio se carga. Lo mejor que puedo comparar esto que es la carpeta de "Inicio" de windows.
Editar el siguiente archivo:
/home/pi/.config/lxsession/LXDE-pi/autostart
Puede hacerlo a través de una sesión de línea de comandos escribiendo:
sudo nano sudo nano /home/pi/.config/lxsession/LXDE-pi/autostart
Agregar la secuencia de comandos para poner en marcha su programa en la parte inferior del archivo, he utilizado un script SH para inaugurar mi archivo christmas_motion.py. Esto es lo que parece el archivo autostart:
--profile LXDE-pi<br> --desktop --profile LXDE-pi -no-splash <br> ${HOME}/.config/lxsession/LXDE-pi/autokey.sh <br> /home/pi/Documents/pythonprograms/christmas_launcher.sh
Tenga en cuenta los últimos puntos de la línea a mi archivo (christmas_launcher.sh) -mi archivo tiene este aspecto:
#!/bin/sh<br>#christmas_launcher.sh <br>#navigate to directory<br>cd / cd /home/pi/Documents/pythonprograms sudo python christmas_motion.py cd /
El archivo se cerciora de que ejecuto el christmas_motion.py usando SUDO / privilegios de root para lo GPIO pide en el código python que el nivel correcto de permisos para acceder a los pines GPIO, de lo contrario el usuario estándar de "PI" no tiene permisos suficientes para acceder a los pernos del sensor de movimiento.
He intentado lanzar el christmas_motion.py directamente desde el archivo autostart pero resultó en un extraño bucle infinito de lanzando una y otra vez la misma aplicación por lo que recurrí a mi script SH estándar que ha trabajado cada vez.