Stap 3: Het Python programma's schrijven
Ik begon de programmering door zich te concentreren op het verkrijgen van een eenvoudige interactieve touch screen systeem gebruik meestal Tkinter objecten voor het maken van een python GUI. Alle code is opgenomen om het hebben van een kiosk stijl photobooth. De code is opgenomen in een zip-bestand in dit instructable. Na het uitvoeren van dit gedurende een aantal dagen heb ik een paar kleine veranderingen die ik heb gecorrigeerd in de upload zip-bestand en in deze voorbeelden.
Het project bestaat uit drie hoofdprogramma's:
- christmas_motion.py - dit is wat mij voorsprong opwaarts zodra de PI, het controleert de bewegingssensor en wanneer beweging wordt gedetecteerd wordt gecontroleerd of een bestand dat er alleen bestaat wanneer de belangrijkste "christmas_wreath_2.0.py"-programma wordt uitgevoerd. Als het bestand er is het niet iets te doen, als het niet is dan de motie programma aftrap van het hoofdprogramma "christmas_wreath_2.0.py"
- Belangrijkste acties:
- Monitor resolutie
- Kick-off christmas_wreath_2.0.py
- Sluit de screensaver "feh"
- Belangrijkste acties:
- christmas_wreath_2.0.py - dit is het hoofdprogramma, het doet vier dingen:
- Vraag van de bezoeker aan uw deur, als ze willen een "Elfie" foto
- Neem / heroveren van foto 's
- Afdrukken
- Sluit af
- christmas_nowprinting.py - dit wordt gebruikt voor het weergeven van een geanimeerd GIF van een printer. Omdat de printer bluetooth duurt de afdruktaak ongeveer twee minuten. Nadat dit is gebeurd het bestand verhinderen dat de motie programma kick-off van een nieuwe "Take Elfie" program (christmas_wreat_2.0.py"wordt verwijderd en ons proces weer hervat.
Code:
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()
Krijgen de PI aan AutoStart de Tkinter op basis Python app met de gebruikerssessie
Dat is een mondvol maar in principe kunt u niet alleen het uitvoeren van deze tkinter afhankelijke python app vanaf de opdrachtregel in een console enige omgeving, je moet in een x-windows of LXDE sessie, aka, een normale Linux desktop - geen telnet of SSH want dit een app GUI is. Om dit te doen op een raspberry PI, er is een specifieke autostart-bestand dat u bewerkt die wordt uitgevoerd met GUI OR non-GUI apps na het bureaublad wordt geladen. Het beste wat dat ik kan dit vergelijken is de map windows "startup".
Bewerk het volgende bestand:
/home/pi/.config/lxsession/LXDE-pi/autostart
U kunt dit doen via een opdrachtregel-sessie door te typen:
sudo nano sudo nano /home/pi/.config/lxsession/LXDE-pi/autostart
Voegt u uw script aan uw programma aftrap aan de onderkant van het bestand, gebruikte ik een SH script aftrap van mijn christmas_motion.py-dossier. Hier is wat de autostart-bestand ziet er als:
--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
Let op de laatste regel verwijst naar mijn Launcher-bestand (christmas_launcher.sh) -mijn launcher-bestand ziet er als volgt:
#!/bin/sh<br>#christmas_launcher.sh <br>#navigate to directory<br>cd / cd /home/pi/Documents/pythonprograms sudo python christmas_motion.py cd /
De launcher-bestand zorgt ervoor dat ik lopen de christmas_motion.py met behulp van SUDO / root-privileges zodat de GPIO in de python-code aanvragen het juiste niveau van machtigingen hebben voor toegang tot de GPIO pinnen, anders heeft de standaard gebruiker "PI" niet voldoende machtigingen voor toegang tot de beweging sensor pinnen.
Ik probeerde de lancering van de christmas_motion.py rechtstreeks uit de autostart-bestand maar het resulteerde in een rare oneindige lus van kick-off van de zelfde app over en weer dus ik toevlucht terug naar mijn standaard SH script dat heeft elke keer gewerkt.