Kühlschrank - Essen vorm Verderben schützen

  • Hallo,

    wir haben zuhause oft das Problem, dass Lebensmittel im Kühlschrank in Vergessenheit geraten. Daher möchte ich mir ein Skript schreiben, dem ich sage:

    1. was ich in den Kühlschrank lege

    2. wie lange es haltbar ist - um kurz vor Ablauf gewarnt zu werden

    3. wann ich etwas anbreche (um dann in einer liste zu sehen, was schon am längsten geöffnet ist)


    Ich habe gegoogelt was es schon so gibt und bin unter anderem auf diese Seite gestoßen. Daran würde ich mich gerne orientieren und haben zunächst ein paar Fragen zum Skript:

    1. Ich glaube die Seite ist schon etwas älter. Ist das Skript so noch in Ordnung? Aus while(1): mache ich while True:?

    2. In diesem Skript werden werden ja zwei Wörter benötigt. Das erste ist der command, das zweite das item. Hier wird es mit einem dictionary gemacht.


    Für meine Zwecke bräuchte ich ja nun manchmal mehr Einträge. Bsp.:

    Kommando Lebensmittel Anzahl Ablaufdatum
    hinzufügen Sahne 2 22.12.2018
    geöffnet Sahne


    Bei geöffnet müsste ich dann noch das Datum mit einbinden um dann anzeigen zu lassen wie lange es schon geöffnet ist. Aber vorher zunächst einmal die Frage, wo genau ich meine vier parsedCommands speichere?

    Wenn ich das richtig verstanden habe speicher ich im dictionary nur zwei Einträge. Es sei denn ich mache es mit einem Tuple. Empfiehlt sich das? Oder eher eine Liste?


    Ich würde mit euren Tipps einmal anfangen zu schreiben und bei Problemen noch mal hier schreiben, bin aber auch für Tipps/Anregungen zum Projekt offen. Evtl. gibt's es etwas vergleichbares ja sogar schon und ich habe es nur nicht gefunden ^^


    Gruß, Tom

  • Schönes Thema, in unserer Zeit wird ja leider viel weggeworfen bei dem eine solche einfache Logik sicher helfen kann. Von daher werde ich mich hier mal ranhängen sobald ich mit meinem aktuellen Projekt durch bin. Bin nur leider kein Skript-Profi, von daher wäre es schön wenn sich der ein oder andere Profi mit unterstützen könnte ;)


    LG MickY

  • Ist der Aufwand nicht viel zu gross im Verhältnis zum Nutzen? Die Datenbank muss ja immer geführt werden. Normalerweise wird ein Kühlschrank mehrmals am Tag geöffnet um Sachen reinzulegen oder herauszuholen. Da hat man jeweils eine Kontrolle. Eine gewisse Übersicht vorausgesetzt natürlich. :)

  • Servus Tillmario,

    nettes Projekt basierend auf einer netten Idee ... aber imho nicht alltagstauglich.

    Meine Meinung: Du wirst in der ersten Begeisterung das Ganze penibel führen aber im danach wird Dir der Aufwand einfach lästig. Ist mir in der Vergangenheit mit allen meinen eigenen Verwaltungsprogrammen ( CDs, DVDs, elektronischen Bauteilen, 3D-Drucker Ersatzteile ...) so gegangen.

    Aber eine schöne Beschäftigung mit viel Lernpotential ( evtl. Artikel über die EAN - Stichwort Barcode - ermitteln, MHD per Kamera/Smartphone einscannen statt tippen, Packungen/Gläser zur schnellen Identifizierung mit eigenen RFID Tags versehen, Mindestbestand kontrollieren, ...).


    Für den echten "Dauereinsatz" würde ich so was für eine evtl. vorhandene Gefriertruhe oder im Keller langzeitgelagerte Lebensmittel machen - aber auch nicht wirklich ;) .


    btw: MHD ... viele Lebensmittel sind weit über das angegebene MHD noch ohne gesundheitliche Gefahren oder Geschmackseinbußen verzehrbar.

    Ach ja: wie willst Du das mit Obst, Salat, Eiern, ... realisieren?


    cu,

    -ds-

  • Danke für eure Antworten, die wichtigste Aufgabe dieses Skripts sehe ich darin mir zu sagen wann Dinge geöffnet worden sind.

    Es kommt wirklich oft vor, dass meine Frau mich fragt wie lange die Sahne schon auf ist, ich es nicht weiß und sie die Sahne dann aus vorsicht wegmacht.


    Wenn auf dem RPi mit LCD Display angezeigt wird:

    Lebensmittel geöffnet seit (in Tagen)
    Sahne 3
    Kochschinken 4


    Wie das Projekt im Endeffekt aussieht ist noch irrelevant. Es wird sich eh noch x Mal verändern. Ich hatte befürchtet, dass die Diskussion in die Richtung geht. ^^

    Es geht mir nun wirklich erstmal um meine Programmierungsfrage, damit ich anfangen kann rumzuprobieren.

    Aus while(1): mache ich while True:?

    Im Ursprungsskript sonst irgentetwas zu beanstanden, was ich vorher abändern sollte?


    Und wo drin speicher ich meine bspw. 4 Terme, die ich einspreche? Geht es irgendwie mit dict() oder ist das nicht empfehlenswert?


    Gruß, Tom

  • Das Projekt an sich ist ja nicht uninteressant, wie schon angemerkt wurde. Es will dich hier sicherlich keiner davon abhalten. Wegen dem Skript kann ich leider nicht helfen.


    ps: Die Beispiele mit der Sahne und Kochschinken laden gerade dazu ein. :D Wann geöffnet wurde ist nicht wichtig. Ob man diese noch verzehren kann, lässt sich durch Sichttest, Geruchstest und ggf. Geschmackstest ermitteln. Feste Verfallstermiene gibt es ja nicht. Es ist wirklich so einfach.

  • Wann geöffnet wurde ist nicht wichtig.

    Aber zu wissen, dass etwas geöffnet ist, ist bei uns wichtig. Nach drei Wochen braucht man auch nicht mehr riechen. Und genau das ist unser Problem und wurde auch im ersten Satz beschrieben. Lebensmittel werden vergessen. So wie der von mir kürzlich entdeckte Gouda, der schon fast mehr Schimmel als Käse war. ^^

    Daher: Liste was offen ist und demnach zuerst verbraucht werden sollte und alles ist gut.


    Ich habe mich jetzt auch erstmal zu folgendem Entschieden:

    Welche Produkte im Kühlschrank sind -> egal.

    MHD -> egal.

    Einfach sagen was rausgenommen wird und anzeigen lassen, was wie lange offen ist.


    Ich habe auch mal angefangen und stoße auf mein erstes Problem.


    Code
    import datetime
    items = dict()
    
    today = datetime.date.today()
    x = input('Welches Lebensmittel wurde geöffnet? ')
    print(today)
    items[x] = today
    print(items)

    print(today) liefert "2018-12-13" aber print(items) liefert {'Sahne': datetime.date(2018, 12, 13)}
    Wie kann ich im dictionary den ersten Wert abspeichern? Ich muss ja im Endeffekt darauf zugreifen und dann den Wert vom aktuellen Datum abziehen.


    Gruß, Tom

  • print(today) liefert "2018-12-13" aber print(items) liefert {'Sahne': datetime.date(2018, 12, 13)}
    Wie kann ich im dictionary den ersten Wert abspeichern? Ich muss ja im Endeffekt darauf zugreifen und dann den Wert vom aktuellen Datum abgezogen.

    Dass du das Datum im Format "YYYY-MM-DD" erhältst, liegt an der magic-method __str__ des datetime.date-Objekts. Das Datum als solches und nicht als String zu speichern ist aber guter Stil und vereinfacht Berechnung massiv - also lasse es so, wie es ist ;)


    Edit: siehe https://docs.python.org/3/refe…model.html#object.__str__ (und __repr__ darüber)

  • Ich glaube auch, dass das System nicht nachhaltig gepflegt wird...

    Nimm einen Permanent-Filzstift und schreib auf alle Packungen das Öffnungdatum drauf - da hast du mehr davon.

    Und dann noch ein paar leuchtgrüne Bapper, die sagen "Iss mich schnell auf!" - die klebt jeder auf Sachen, von denen er bemerkt, dass sie bald fällig sind.

    Ansonsten gilt: FIFO - First In First Out. Neue Sachen nach hinten räumen, offene und verderbliche Sachen nach vorne, damit man sie gut sieht.

    Und vielleicht mal mit der Familie reden, warum neue Sachen aufgemacht werden, obwohl noch offene, ältere da sind. Mir scheint das keine Frage von "vergessen" zu sein, sondern eher eine von "ich ess nichts, was es gestern schon mal gab". Wenn fünf Sorten Käse offen sind, isst natürlich jeder den frischsten und neusten. Da hilft dir die Datenbank auch nicht.


    Und wenn du es unbedingt machen willst... vielleicht kannst du das Handling über die EAN-Codes und einen Scanner erleichtern. Wer will schon in der Datenbank langwierig nach den Lebensmitteln suchen und alles händisch einpflegen. Es gibt im Internet EAN-Datenbanken, da kannst du vielleicht sogar die Produktnamen gleich abfragen.

    Und einen Türkontakt an den Kühlschrank, damit der Pi beim Öffnen per Sprachmodul auf zu essende Lebensmittel hinweisen kann. "Krrz, KESE krr SCHIN KEN brrrr SCHAM PAG NER zzkrr..." ;)

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • Aber zu wissen, dass etwas geöffnet ist, ist bei uns wichtig. Nach drei Wochen braucht man auch nicht mehr riechen. Und genau das ist unser Problem und wurde auch im ersten Satz beschrieben

    wobei Deine Vorstellung "broken by design" ist, wie man so schön sagt.

    Es besteht ein gewaltiger Unterschied, ob das angebrochene Lebensmittel direkt wieder in den Kühlschrank wandert oder einige Zeit bei Raumtemperatur irgendwo rumsteht.

    Um eine "Riech-/Geschmascksprobe" wirst Du also nicht drum herum kommen.

    Und angebrochene Lebensmittel sind mit einem Blick identifiziert ... da braucht man keine aufwändige Verwaltungssoftware.


    Wie ich hier schon schrieb ... ein nettes Lernprojekt mit viel Erweiterungs-Potential.

    Aber als ernsthafte Anwendung kannst Du das wohl vergessen.


    cu,

    -ds-

  • Ich glaube auch, dass das System nicht nachhaltig gepflegt wird...

    Sorry, aber ob du das glaubst oder nicht tut doch hier überhaupt nichts zur Sache. Die Prämisse ist, dass es gepflegt wird. Das ist anzunehmen. Deine anderen Anmerkung empfinde ich als Off-Topic, es geht mir mitlerweile nur noch um's Programmieren.

    Dass du das Datum im Format "YYYY-MM-DD" erhältst, liegt an der magic-method __str__ des datetime.date-Objekts. Das Datum als solches und nicht als String zu speichern ist aber guter Stil und vereinfacht Berechnung massiv - also lasse es so, wie es ist ;)

    Vielen Dank für die Tipps. Ich hänge momentan an folgender Stelle. Ich habe ein dictionary mit bspw.:

    {'Wurst': datetime.date(2018, 12, 12), 'Sahne': datetime.date(2018, 12, 13), 'Bonbon': datetime.date(2018, 12, 11), 'Kochschinken': datetime.date(2018, 12, 10)}


    wie hole ich da jetzt die Daten raus?

    for .... in food:

    key = aktuelles datum - value


    sodass ich eine Liste mit geöffneten Lebensmitteln bekomme:

    Wurst 1

    Sahne 0

    Bonbon 2

    Kochschinken 3


    Gruß, Tom

  • Ganz einfach:

    Das ist das tolle: wenn du ein datetime.date von einem anderen datetime.date abziehst, bekommst du ein datetime.timedelta. Dieses hat unter anderem ein Attribut days, welches du verwenden kannst. Siehe https://docs.python.org/3.7/library/datetime.html:

    class datetime.timedelta

    A duration expressing the difference between two date, time, or datetime instances to microsecond resolution.

    timedelta-Doku: https://docs.python.org/3.7/li…e.html#datetime.timedelta.

  • Wow, vielen Dank für die ausführliche Antwort. Mit dem Attribut days habe ich schon experimentiert, aber diese for Konstruktion konnte ich mir nicht selber herleiten.

    Ich werde Mal versuchen das zu verstehen und es dann ins Skript einzubauen.

    Danke nochmal.

  • Okay, ich habe jetzt mal versucht deine Tipps auf mein Projekt anzuwenden. Prinzipiell geht es nur noch darum das Ganze mit tkinter auf dem Display zu visualisieren.

    Ich habe überlegt, wie ich die "dictionary"-Einträge anzeigen lassen soll und habe versucht es mit range(1 - Anzahl der Einträge im Dict (+1) zu machen und dann im grid anzuzeigen.

    Mir werden im Fenster allerdings nur 3 items angezeigt, obwohl 4 drin sind.

    Aber zunächst einmal: Habe ich das überhaupt richtig gemacht? ^^

    Gruß, Tom


  • Ich tippe mal auf: range(0 - Anzahl der Einträge im Dict (+1)

    So ist es. Mit einem Counter und Indizierung zu arbeiten ist aber nicht sehr "pythonisch", das macht man so:

    Python
    for name, date in food.items():
        days_open = (datetime.date.today() - date).days
        label_name = Label(
            master=window, font=("Arial", 10), text=name
        )
        label_days= Label(
            master=window, font=("Arial", 10), text=days_open
        )
        label_name.grid(row=i,column=1)
        label_days.grid(row=i,column=2)

    Den Tkinter-Code solltest du besser noch in eine oder mehrere Funktionen auslagern, denn guter Stil ist es, auf Modulebene nur Imports, Konstanten und Klassen/Funktionsdefinitionen zu haben.

    Die Zeilen 19-22 müssen weiter eingerückt werden.


    Ich empfehle ebenfalls einen Blick auf https://github.com/ambv/black und https://www.python.org/dev/peps/pep-0008/! Wenn man PEP 8 folgt, wird der Code fast immer automatisch besser lesbar, und mit einem Formatter wie "black" kannst du deine Energie in das schreiben von Code, nicht Formatieren von Code stecken.

  • Python
    for name, date in food.items():
        days_open = (datetime.date.today() - date).days
        label_name = Label(
            master=window, font=("Arial", 10), text=name
        )
        label_days= Label(
            master=window, font=("Arial", 10), text=days_open
        )
        label_name.grid(row=i,column=1)
        label_days.grid(row=i,column=2)

    Danke für eure Tipps. Daran dass der erste Eintrag 0 ist habe ich nicht dran gedacht. Der Code von dir liefert mir:

    [Blocked Image: https://i.imgur.com/7zPiJnH.png]


    Wenn ich es mit meiner vorherigen Variante mache klappt es zwar.

    [Blocked Image: https://i.imgur.com/dnmguFQ.png]

    Aaaaber:

    Ich habe mal das Skript so bearbeitet um beim button_öffnen einen Eintrag in's dictionary zu machen und es danach anzuzeigen. Dummerweise sieht es dann so aus:

    [Blocked Image: https://i.imgur.com/ga4gct9.png]


    Es wird also in eine Zeile zweimal geschrieben. Eigentlich müsst doch bis row=6 geschrieben werden. :conf:


    Hier das aktuelle Skript:

  • Hier das aktuelle Skript:

    Code
    Traceback (most recent call last):
      File "test.py", line 37, in <module>
        button_entfernen.grid(row= 2,column=0)
    NameError: name 'button_entfernen' is not defined


    okay, mit einem hinzugefügten global food_count funktioniert es

    Versuche, globale Variablen so gut wie möglich zu vermeiden - oder wie noisefloor sagen würde: vergiss ganz schnell wieder, dass es global überhaupt gibt.


    dann wäre jetzt nur noch die frage, warum dein code nicht klappt.

    Ich habe zwar übersehen, dass du i noch verwendest, es ist aber nicht als fertige Lösung gedacht, sondern als Anregung. Man kann nun mal über eine ganze Reihe von Python-Typen direkt iterieren, ohne sich einen Index hoch zu zählen, und wenn man dann doch mal einen braucht, kann man auch enumerate() nehmen.


    Wenn es eine Fehlermeldung gibt, poste sie. Wenn der Code nicht das macht, was er machen soll: beschreibe das Problem. Und vorallem lade Bilder direkt im Forum hoch (als Anhang oder mit copy&paste), die verbleiben viel eher im Forum und es ist weniger Aufwand für die Helfenden, die Bilder anzuschauen.

  • Hallo,


    pack' das ganze in eine Klasse - was bei GUI außer ultra-trivialen so wie so seeeeehr sinnvoll ist - mach' das Dict mit den Lebensmitteln zu einem Attribute und die Anzahl der Lebensmittel zu einer `property`, dann ist dein Problem gelöst.


    Ich würde das ganze auch web-basiert machen - hier bietet sich IMHO Django an - dann kannst du auf die Liste von jedem Geräte im Heimnetzwerk (Smartphone, Tablet, alle Laptops etc.) zugreifen.


    Gruß, noisefloor