TKinter+RFID+DB

Fragen zu Tkinter.
Antworten
Lutz82
User
Beiträge: 4
Registriert: Mittwoch 21. März 2018, 21:53

Hallo,

ich bin neu hier im Forum und neu was das Thema Python angeht.
Habe einige Projekte mit PHP und mysql umgesetzt.

Nun möchte ich an einem Rasperry PI 3 eine Arbeitszeiterfassung programmieren.
Ich habe bereits ein GUI (TKinter)
Der mir das aktuelle Datum und Uhrzeit anzeigt

In einem anderem Skript funktioniert das auslesen der RFID Chips.

Im ersten Schritt möchte Ich nun das TKinter/GUI mit laufender Uhrläuft und der RFID chip trotzdem ausgelesen wird.

Ich schaffe es nicht, dass die beiden Skripte GLEICHZEITIG ausgeführt werden.
Habe einiges ausprobiert. Könnt ihr mir helfen?
Gerne mit Beispiel Skripten.
Habe es schon mit Threading versucht, aber ich komme nicht weiter.

(Wenn sich jemand an dem Projekt beteiligen möchte, kann er mir gerne eine PM Schicken.)

Danke für Eure Hilfe

Gruß Lutz
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

zeig doch was du versucht hast, dann kann man Dir viel besser helfen.
Lutz82
User
Beiträge: 4
Registriert: Mittwoch 21. März 2018, 21:53

folgende beiden Code sind meine Grundlage

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf8 -*-
#
#    Copyright 2014,2018 Mario Gomez <mario.gomez@teubi.co>
#
#    This file is part of MFRC522-Python
#    MFRC522-Python is a simple Python implementation for
#    the MFRC522 NFC Card Reader for the Raspberry Pi.
#
#    MFRC522-Python is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Lesser General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    MFRC522-Python is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Lesser General Public License for more details.
#
#    You should have received a copy of the GNU Lesser General Public License
#    along with MFRC522-Python.  If not, see <http://www.gnu.org/licenses/>.
#

import RPi.GPIO as GPIO
import MFRC522
import signal
import time


continue_reading = True

# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
    global continue_reading
    print "Ctrl+C captured, ending read."
    continue_reading = False
    GPIO.cleanup()

# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)

# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()

# Welcome message
#Lutz print "Welcome to the MFRC522 data read example"
#Lutz print "Press Ctrl-C to stop."

# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:
    
    # Scan for cards    
    (status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)

    # If a card is found
   # if status == MIFAREReader.MI_OK:
    # print "Card detected"
    
    # Get the UID of the card
    (status,uid) = MIFAREReader.MFRC522_Anticoll()

    # If we have the UID, continue
    if status == MIFAREReader.MI_OK:

        # Print UID
        card_id= str(uid[0]) + str(uid[1]) + str(uid[2]) + str(uid[3])
	print card_id
    
	time.sleep(3)

und der Code für das GUI

Code: Alles auswählen

#import tkinter as tk

import time
import tkinter
from tkinter import *
#fenster = Tk()

class FullScreenApp(object):
    def __init__(self, master, **kwargs):
        self.master=master
        pad=3
        self._geom='200x200+0+0'
        master.geometry("{0}x{1}+0+0".format(
            master.winfo_screenwidth()-pad, master.winfo_screenheight()-pad))
        master.bind('<Escape>',self.toggle_geom)            
    def toggle_geom(self,event):
        geom=self.master.winfo_geometry()
        print(geom,self._geom)
        self.master.geometry(self._geom)
        self._geom=geom


root=Tk()
root.title("Arbeitszeiterfassung") # ändert den Titel

uhr = Label(master=root,
            font=('Arial',10),
            fg='blue',
            width = 15,
            height = 2)
uhr.pack()

datum = Label(master=root,
            font=('Arial',10),
            fg='blue',
            width = 15,
            height = 1)
datum.pack()

kommen = Label(master=root,
            font=('Arial',10),
            fg='green',
            width = 15,
            height = 2)
kommen.pack()

gehen = Label(master=root,
            font=('Arial',10),
            fg='green',
            width = 15,
            height = 2)
gehen.pack()


mitarbeiter = Label(master=root,
            font=('Arial',10),
            fg='blue',
            width = 15,
            height = 2)
mitarbeiter.pack()

date = ''
zeit = ''
kommenlabel='KOMMEN'
gehenlabel='Gehen'
anrede='HERR oder frau XXXX'

kommen.config(text = kommenlabel)
gehen.config(text = gehenlabel)
mitarbeiter.config(text = anrede)


def tick(  ):
    global zeit
    neuezeit = time.strftime('%H:%M:%S')
    neuesdatum = time.strftime('%d.%m.%Y')
    if neuezeit != zeit:
        zeit = neuezeit
        uhr.config(text = zeit)
        datum.config(text = neuesdatum)
    uhr.after(200, tick)

    
tick()

app=FullScreenApp(root)
root.mainloop()
meine Versuche es zusammenzuführen sind noch nicht sehr weit...
da ich es mit dem Ansatz von

Code: Alles auswählen

import thread
import time

# Define a function for the thread
def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print "%s: %s" % ( threadName, time.ctime(time.time()) )

def print_date( threadName, delay):
   count2 = 0
   while count2 < 5:
      time.sleep(delay)
      count2 += 1
      print ( threadName, time.ctime(time.time()) )

# Create two threads as follows
try:
   thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   thread.start_new_thread( print_time, ("Thread-2", 4, ) )
   
except:
   print "Error: unable to start thread"

while 1:
   pass
aber ich verstehe nit, wie ich das mit thread ausführen könnte... da im nächsten schritt auch noch die Anbindung an die db folgen soll...

oder ist die Scriptsprache für das Projekt nicht ideal?

Für jede Hilfe bin ich dankbar
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Lutz82

Hier ein Versuchsskript um die Übergabe eines sich ändernden Zählerwertes aus einem Thread an eine Tkinter after.loop mittels Queue zu zeigen. Der GUI-Teil musste ich für meinen Versuch anpassen. Ist aber nicht ganz meine Art eine GUI zu erstellen:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import threading
import queue as qu
import time

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk

APP_TITLE = "Arbeitszeiterfassung"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 300
APP_HEIGHT = 300

QUEUE_SIZE = 10
POLLING_TIME = 100   # Milliseconds


class CounterThread(threading.Thread):
    
    def __init__(self, queue=None, delay=0.3):
        self.queue = queue
        self.delay = delay
        self.counter = 0
        
        threading.Thread.__init__(self)
        self.start()

    def run(self):
        while True:
            num_count = 0
            time.sleep(self.delay)
            self.counter += 1

            self.queue.put(self.counter)
            self.queue.join()
    
class Application(object):

    def __init__(self, app_win):
        self.main_win = app_win
        self.zeit = ''
        
        self.build()
        
    def build(self):
        self.main_frame = tk.Frame(self.main_win, relief='groove', bd=2)
        self.main_frame.pack(expand=True)
        
        self.uhr = tk.Label(self.main_frame,
                    font=('Arial',10),
                    fg='blue',
                    width = 15,
                    height = 2)
        self.uhr.pack(padx=5)

        self.datum = tk.Label(self.main_frame,
                    font=('Arial',10),
                    fg='blue',
                    width = 15,
                    height = 1)
        self.datum.pack()

        kommen = tk.Label(self.main_frame,
                    font=('Arial',10),
                    fg='green',
                    width = 15,
                    height = 2)
        kommen.pack()

        gehen = tk.Label(self.main_frame,
                    font=('Arial',10),
                    fg='green',
                    width = 15,
                    height = 2)
        gehen.pack()

        mitarbeiter = tk.Label(self.main_frame,
                    font=('Arial',10),
                    fg='blue',
                    width = 15,
                    height = 2)
        mitarbeiter.pack()

        # Display for a thread driven counter
        self.var_counter = tk.IntVar()
        tk.Label(self.main_frame, textvariable= self.var_counter, font=('Arial',
            20, 'bold'), fg='red').pack(fill='x')
        self.var_counter.set(0)
        
        kommen.config(text='KOMMEN')
        gehen.config(text='Gehen')
        mitarbeiter.config(text='HERR oder frau XXXX')

        self.queue = qu.Queue(QUEUE_SIZE)
        self.app_thread = CounterThread(self.queue)
        self.tick()

    def tick(self):
        neuezeit = time.strftime('%H:%M:%S')
        neuesdatum = time.strftime('%d.%m.%Y')
        if neuezeit != self.zeit:
            self.zeit = neuezeit
            self.uhr.config(text=self.zeit)
            self.datum.config(text=neuesdatum)
            
        self.queue_polling()    
        self.main_win.after(POLLING_TIME, self.tick)

    def queue_polling(self):
        if self.queue.qsize():
            try:
                data = self.queue.get()
                self.var_counter.set(str(data))
                self.queue.task_done()
            except qu.Empty:
                pass


def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Lutz82: das mit dem Zusammenkopieren von irgendwelchen Skripten aus dubiosen Quellen, ist immer das Problem, dass sie meist so schlecht strukturiert sind, dass es nicht möglich ist, sie für komplexere Dinge wiederzuverwenden.

Du hast Dir zum Start drei für sich genommen sehr komplexe Themen herausgesucht und willst sie alle drei auf einmal angehen. Threads, die miteinander kommunizieren wollen, erfordert Wissen, wie man das richtig macht. Da es dazu meines wissens keine gute Einstiegsliteratur gibt, bleibt Dir nur die Möglichkeit, Dich Sprachunabhängig mit Threads einzulesen und die Pythondokumentation dazu durchzuarbeiten und dich mit der API vertraut zu machen. Bei GUIs sind leider 99.9% der Beispiele, die man finden kann, nur für simpelste Fälle geeignet und für komplexere Programme muß man einen völlig anderen Ansatz wählen. Leider begnügt sich auch die komplette Literatur dazu auf simpelste Fälle, so dass man sich, wenn man vom einfachsten zu komplexeren GUIs geht, sich selbst durchkämpfen muß (was nicht heißen soll, dass man mit Python und TkInter nicht auch komplexe GUIs schreiben kann.) Dein Beispiel, z.B., hat nur ein nicht Dummyklasse, wo nicht konsequent daran weiter gearbeitet wurde, sondern dann in den Spaghetti-Code-Modus gewechselt wurde. Dritter Themenkomplex: RasPi mit Hardwareansteuerung. DA tummeln sich auch Millionen von Miniskripte, die gerade so funktionieren, bei der kleinsten Störung aber zusammenbrechen (und Störungen treten bei Hardware quasi immer auf).

Will man jetzt alles kombinieren, treten erst die Kombinationsschwierigkeiten auf. GUIs dürfen nur aus dem Hauptthread angefasst werden und reagieren auf Verzögerungen sehr empfindlich. Hardware will eigentlich immer die ganze Aufmerksamkeit und reagiert empfindlich, wenn ihr der Thread unter den Füßen weggezogen wird oder mehrere Dinge parallel passieren. Wenn man da also nicht wirkliche ALLES versteht, was man selbst tut und was dazu noch im Hintergrund abläuft, steht man oft vor der Frage, warum das gerade noch getan hat, jetzt aber plötzlich nicht mehr.

Das soll Dich jetzt nicht entmutigen, sondern nur darauf vorbereiten, dass Du einen langen Weg mit Deinem Projekt vor Dir hast. Dass Du viel Experimentieren mußt, aber Experimentieren im Sinne von Systematisch Versuchen, das System zu verstehen, denn ohne Verständnis kann man solche komplexen Verknüpfungen nicht programmieren.

Das Forum kann Dir dabei aber auch nur soweit helfen, konkrete Fragen zu lösen. Da kaum jemand die Hardware haben dürfte und auch niemand die exakt gleiche Konfiguration, reicht es nicht zu sagen, irgendwas tut nicht.

Konkrete Tipps: arbeite strukturiert und sauber. Halte Dich an die Regeln, die Helfen Dir und uns, Dir zu helfen. Dazu gehören, sprechende Variablen und Funktionsnamen, was in den Beispielen ja schon der Fall ist. Das RFID-Beispiel benutzt Signale, hier falsch und auch sonst eigentlich nie sinnvoll. Das GUI-Beispiel enthält *-Importe und global. Beides sind keine Lösungen, sondern nur Quelle von Problemen. Also nie verwenden. Das thread-Beispiel verwendet die veraltete thread-API, statt threading, hat die falsche Einrückung (Eingerückt wird immer mit 4 Leerzeichen) und verwendet eine Busy-Loop um die Wohnung zu heizen.

Programmieren ist wie malen. Die meisten bekommen nur Gekrizel hin oder Malen nach Zahlen. Mit etwas Übung kann man nach Vorlage malen. Aber kreativ eigene Werke zu erstellen, braucht viel Übung und Ausdauer.
Antworten