Shuttersteuerung V1.1

Die Version 1.1 enthält nun auch die Statusabfrage und zeigt an ob der Shutter offen oder geschlossen ist. Dafür nutze ich wieder ein PJLink Kommando. Mit den Kommandos "%1AVMT=30" bzw. "%1AVMT=31" wird der Shutterstatus gesetzt und mit dem Kommando "%1AVMT ?" wird der aktuelle Zustand ausgelesen. Der Beamer antwortet dann mit "%1AVMT=30" bzw. "%1AVMT=31".
Für diese Abfrage gibt es die Funktion "abfrage_shutter()", die auch in einem eigenen Thread läuft. Damit der Beamer nicht mit Abfragen geflutet wird, habe ich nach jeder Abfrage fünf Sekunden Wartezeit eingebaut.

Des Weiteren habe ich noch eine mögliche Fehlerquelle abgefangen, die das Programm zum Absturz gebracht hat. Wenn keine MIDI Schnittstelle vorhanden ist, wird das angzeigt und das Programm kontrolliert beendet.

Um das Programm besser an eine neue Umgebung anpassbar zu machen werden die IP Adresse und der PJLink Port des Beamers in globalen Variablen zu Beginn des Programms definiert.
Image
import tkinter as tk
from pygame import midi
import socket
import threading
import sys
from time import sleep

# Globale Variablen

ip = '192.168.20.68'
port = 4352


#PJLink Funktionen

def abfrage_shutter():    #Funktion zur Abfrage des Shuttersstatus
    msg = '%1AVMT ?\r'    #Zu sendende PJLink Nachricht
    msg = msg.encode('UTF-8')
    while True:
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((ip, port))
            data = s.recv(1024)
            s.send(msg)
            data = s.recv(1024)
            if data.decode() == '%1AVMT=30\r':    #Wenn Antwort vom Beamer = %1AVMT=30
                status = 'Shutter ist offen'
            if data.decode() == '%1AVMT=31\r':    #Wenn Antwort vom Beamer = %1AVMT=31
                status = 'Shutter ist geschlossen'
            s.close()
            for i in range(5):    #5 Sekunden warten und jede Sekunde einen Punkt scheiben
                sleep(1)
                shutterstatus.set(status + '.'*i)
        except:
            shutterstatus.set('Fehler! Beamer nicht erreichbar')

def shutter(aktion):
    if aktion == 'zu':
        msg = '%1AVMT 31\r'
    elif aktion == 'auf':
        msg = '%1AVMT 30\r'
    msg = msg.encode('UTF-8')
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((ip, port))
    s.send(msg)
    s.close()
    

#MIDI Funktionen

def midi_decode(key):
    
    #prüfe auf Note on Status, gib Note on Status und Midinote zurück
    
    if key[0] == 144:
        s = True
    else:
        s = False
    
    n = key[1]
    return s, n

def midi_eingabe():
    
    #warte auf MIDI Input Signal und löse Shutter Funktion aus
    
    while True:
        if midi_input.poll():
            eingabe = midi_input.read(num_events=16)
            note_on, taste = midi_decode(eingabe[0][0])
            if note_on and taste == 125: #F8
                shutter('zu')
            if note_on and taste == 127: #G8
                shutter('auf')

    
#GUI Funktionen

def callback(event):
    
    #Tastatursteuerung
    
    if event.keysym == 'x':
        fenster.destroy()
    if event.keysym == 'a':
        shutter('auf')
    if event.keysym == 'z':
        shutter('zu') 
          
def erlaube_tastatur_eingabe():
    fenster.bind('<Key>',callback)
               
#Initialisiere Midi Schnittstelle               

try:             
    midi.init()
    default_id = midi.get_default_input_id()
    midi_input = midi.Input(device_id=default_id)
except:    #Fehlermeldung wenn kein MIDI Interface vohanden ist
    b = 300 #Fensterbreite
    h = 100 #Fensterhöhe
    fehler = tk.Tk()
    x = int(fehler.winfo_screenwidth()/2 - b/2) #X-Position für Bilschirmmitte berechnen
    y = int(fehler.winfo_screenheight()/2 - h/2) #Y-Position für Bildschirmmitte berechnen
    fehler.geometry(f"{b}x{h}+{x}+{y}")
    fehler.title("FEHLER")
    text = tk.Label(fehler, text="FEHLER: Kein MIDI Interface gefunden")
    text.pack()
    beenden = tk.Button(text="Beenden", command=fehler.destroy)
    beenden.focus()
    beenden.pack(pady=20)
    fehler.mainloop()
    sys.exit()
    

#Erstelle GUI

fenster = tk.Tk()
fenster.geometry("300x250")
fenster.title("Shuttersteuerung V1.1.0")
text1 = tk.Label(fenster, text="Dieses Tool übersetzt MIDI Noten")
text1.grid(row=1,column=1,columnspan=2)
text2 = tk.Label(fenster, text="in PJLink Kommandos für Panasonic Beamer")
text2.grid(row=2,column=1,columnspan=2)
text3 = tk.Label(fenster, text="Shutter auf:")
text3.grid(row=3,column=1)
text4 = tk.Label(fenster, text="Channel 1, G8")
text4.grid(row=3,column=2)
text5 = tk.Label(fenster, text="Shutter zu:")
text5.grid(row=4,column=1)
text6 = tk.Label(fenster, text="Channel 1, F8")
text6.grid(row=4,column=2)
shutterstatus = tk.StringVar()
shutterstatus.set('Shutter ist...')
text7 = tk.Label(fenster, textvariable=shutterstatus)
text7.grid(row=5, column=1, columnspan=2,pady=10)
button_auf = tk.Button(text="Shutter auf (a)", command=lambda: shutter('auf'))
button_auf.grid(row=6, column=1, pady=10)
button_zu = tk.Button(text="Shutter zu (z)", command=lambda: shutter('zu'))
button_zu.grid(row=6, column=2, pady=10)

button_quit = tk.Button(text="Beenden (x)", command=fenster.destroy)
button_quit.focus()
button_quit.grid(row=7,column=2, pady=10)
erlaube_tastatur_eingabe()

#Öffne neuen Thread für Midi Input Loop

t1 = threading.Thread(target=midi_eingabe)
t1.daemon = True
t1.start()

#Öffne neuen Thread für Statusabfrage des Shutters

t2 = threading.Thread(target=abfrage_shutter)
t2.daemon = True
t2.start()

#Starte GUI

fenster.mainloop()

#Stoppe alle Threads

sys.exit()