knuspermagier.de https://knuspermagier.de Der private Blog von Philipp Waldhauer Sun, 17 Nov 2024 13:11:41 +0100 de-DE Philipp, der alte Generator <![CDATA[Besondere Maßnahmen]]> https://knuspermagier.de/posts/2024/besondere-ma-nahmen Fri, 04 Oct 2024 09:00:00 +0200 https://knuspermagier.de/posts/2024/besondere-ma-nahmen

Nach drei Jahren trennte ich mich in diesem Jahr von meinem iPhone 13. Also, ich trennte mich nicht wirklich, denn es liegt noch hier herum, falls ich noch irgendeine Banking- oder MFA-App vergessen habe zu übertragen, was halt so anfällt. Außerdem ist es viel zu heruntergerockt um noch irgendeinen vernünftigen Erlös zu erzielen. Ich hatte ja gehofft, dass es mir nochmal so richtig herunterfällt, damit sich das Apple Care-Abo auch lohnt und ich nochmal ein günstiges Austauschgerät bekomme, aber es sollte mir einfach nicht vergönnt sein.

Naja. Jedenfalls habe ich nun ein iPhone 16 und damit endlich USB-C. Was liegt nun näher als endlich alle Lightning-Kabel im Haus zu entsorgen und alles gegen USB-C zu tauschen? Leider gibt es da noch ein paar kleinere Probleme: Ich habe noch ein paar Geräte, die Lightning brauchen, unter anderem meine AirPods Pro und meine AirPods 3, die beide schon recht alt, aber noch in täglicher Benutzung sind. Diese möchte ich gerne, wie auch die Generationen zuvor, weiter verwenden, bis sie kaputt oder verschwunden sind, also brauchte ich eine Lösung! Entweder ein einzelnes Lightning-Kabel am Schreibtisch, und ich muss das Case dann immer genau da laden, oder… ein USB-C-Lightning-Adapter. (danke an @MrWeg)

img_9756.jpeg
Wow, macht das iPhone 16 in leichter Dunkelheit weiterhin furchtbare Fotos.

Natürlich wäre es jetzt nervig, müsste man immer so ein Adaptermanagement betreiben, den dran und wieder abmachen, etc. Also, warum nicht einfach ein bisschen Heißkleber? Sitzt, passt und wackelt nicht. Perfekt. Ja, sieht jetzt etwas dumm aus, aber ich denke, damit kann ich den beiden alten AirPods nun noch ein paar Monate stressfreies Leben ermöglichen.

]]>
<![CDATA[Wie viel sind einhundert Steine?]]> https://knuspermagier.de/posts/2024/wie-viel-sind-einhundert-steine Wed, 25 Sep 2024 10:05:00 +0200 https://knuspermagier.de/posts/2024/wie-viel-sind-einhundert-steine

Als erwachsene Person hat man ja den Vorteil, dass man sich einfach mal ein paar Lego-Steine kaufen kann, um etwas zu bauen. Nach einiger Recherche, wo ich das am günstigsten kann, fiel die Wahl am Ende doch auf Originalsteine von ein paar BrickLink-Händlern. Weder eine Bestellung bei Bluebrixx noch direkt bei Gobricks erschien mir finanziell sinnvoller, bei einfachen 1x4, 1x6, 1x8-Bricks nehmen die sich da alle nicht viel.

Das ging auch alles wunderbar einfach und schnell, BrickLink-Händler sind ja irgendwie ziemlich professionalisiert. Was mich am Ende überraschte, war allerdings, wie wenig einhundert Steine am Ende sind. Hier sind zum Beispiel einhundert 1x1-Bricks.

img_9361.jpeg
img_9363.jpeg
img_9364.jpeg

Ich habe wirklich nachgezählt, weil ich dachte, das kann doch nicht alles sein. Aber so ist es! Anscheinend ist es gar nicht so einfach, sich vorzustellen, wie viel “einhundert” wirklich ist.

]]>
<![CDATA[Devlog #10 - Face ID reloaded]]> https://knuspermagier.de/posts/2024/devlog-10-face-id-reloaded Thu, 01 Aug 2024 18:50:00 +0200 https://knuspermagier.de/posts/2024/devlog-10-face-id-reloaded

Letztens kam ich auf eine Idee. Meine Tagebuch-App ist ja per Face ID vor fremden Augen geschützt und das ist auch gut, aaaber es nervt auch ein bisschen, denn Face ID braucht… Zeit. Vielleicht ist es mein drei Jahre altes iPhone, oder einfach in der Natur der Dinge, aber es dauert schon so 200 - 1000 Millisekunden, bis da was passiert, nachdem ich die App starte. Dann dauert die Erkennung selber nochmal eine gewisse Zeit. Es nervt einfach, wenn man nur kurz was notieren will.

Meine Idee war nun also, das Face ID on Startup rauszunehmen und dafür die Liste der vergangenen Einträge einfach auszublenden und mit einem optionalen Face ID-Knopf auszurüsten. So kann ich einen blitzschnellen App-Start genießen, schnell was aufschreiben, abschicken und fertig. Sollte ich die App zum schmöckern in alten Zeiten nutzen, drücke ich einfach nochmal auf den Button und kann loslegen. Best of both worlds!

Da SwiftUI ziemlich oft einfach auch ziemlich nice ist, klappte der ganze Umbau in gefühlten fünf Minuten! Fühlt sich nun besser an! (Ja, das Icon ist fragwürdig zentriert, aber darum kümmere ich mich später)

]]>
<![CDATA[Für eine direkte Tailscale-Verbindung sorgen]]> https://knuspermagier.de/posts/2024/f-r-eine-direkte-tailscale-verbindung-sorgen Sun, 05 May 2024 12:25:00 +0200 https://knuspermagier.de/posts/2024/f-r-eine-direkte-tailscale-verbindung-sorgen

Wenn man mal über das Tailscale-Netz auf seine NAS zugreifen will und merkt, dass es total langsam ist, könnte es daran liegen, dass man keine direkte Verbindung aufgebaut bekommen hat und alles über einen Relay von Tailscale läuft. In Verbindung mit dem SMB-Protokoll ist das teilweise sehr langsam, ich habe hier nur knapp über 500kbit/s Durchsatz bekommen.

Zum Glück war das Problem recht einfach zu lösen, ich musste nur einmal in der Fritzbox UPnP für die NAS erlauben, also die Möglichkeit, dass sie sich selber Portfreigaben erteilen kann. Einmal Tailscale neugestartet und schwupps, habe ich eine direkte Verbindung und kann Dateien mit mehreren Megabyte pro Sekunde übertragen. Yeah! Weitere Informationen dazu gibt es in der Tailscale Doku.

]]>
<![CDATA[kettcar – Gute Laune ungerecht verteilt]]> https://knuspermagier.de/posts/2024/kettcar-gute-laune-ungerecht-verteilt Mon, 08 Apr 2024 08:55:00 +0200 https://knuspermagier.de/posts/2024/kettcar-gute-laune-ungerecht-verteilt

Auch das neue Album von kettcar ist nach den ersten paar Durchhörungen ziemlich grandios. Bisher ein gutes Musik-Jahr!

]]>
<![CDATA[Alligatoah - off]]> https://knuspermagier.de/posts/2024/alligatoah-off Mon, 25 Mar 2024 23:00:00 +0100 https://knuspermagier.de/posts/2024/alligatoah-off

Ein sehr gutes Album. Ich bin fest davon ausgegangen, dass es gut wird und wurde nicht enttäuscht. Gerne mehr davon!

]]>
<![CDATA[Kassenbons mit OpenAI Vision verstehen]]> https://knuspermagier.de/posts/2024/kassenbons-mit-openai-vision-verstehen Mon, 18 Mar 2024 22:25:00 +0100 https://knuspermagier.de/posts/2024/kassenbons-mit-openai-vision-verstehen

Vor ein paar Monaten habe ich einmal probiert meine Ausgaben mit Firefly III zu tracken, aber ich muss leider sagen, dass es nicht so richtig gefunkt hat. Es ist einfach keine moderne App und lässt an manchen Stellen UX-technisch zu wünschen übrig. Außerdem hat es ein paar Funktionen, wie Budgets und Sparschweine, die ich (gerade) gar nicht brauche.

Was liegt da also näher als es kurz selber zu bauen. Ich hatte ja schon jahrelang eine eigene Lösung im Einsatz, die ich allerdings etwas vernachlässigt habe, da ich keine Lust auf eine uralte Vue 1-App mehr hatte. Danach ging es also zurück zur Excel-Tabelle und zum kurzen, eben erwähnten, Abstecher zu Firefly III.

Ich kopierte mir also eines meiner Standard-Laravel/Livewire-Projekte und klöppelte mir schnell etwas zusammen, was den Firefly-Export lesen konnte und bin schonmal halbwegs zufrieden.


Irgendwann, als ich einen Stapel Kassenbons fand, fiel mir mal wieder mein lange währender Wunsch ein, die zu digitalisieren. Wäre ja schon witzig zu wissen, was man damals eigentlich für 653,21€ bei Obi gekauft hat. Naja. Aber es ist ja immer noch alles nervig dachte ich. Zwar ist OCR-Technologie besser geworden, aber trotzdem müsste man ja noch alles irgendwie auswerten und zuordnen. Zudem stehen auf den Bons ja oft nur absurde Kürzel für die Produkte.

Plötzlich erinnerte ich mich daran, dass es ja OpenAI Vision gibt. Da sah ich in letzter Zeit ein paar verrückte Videos, wo Leute einfach ihr Bücherregal aufnehmen und die AI alle Buchtitel zurück liefert, und ähnliches.

Ich probierte also mal die Vision API mit einem Kassenbon und folgendem Prompt:

Das Bild ist ein Scan von einem Kassenbon. Bitte liefere mir folgende Daten als JSON.

  • Das Datum des Einkaufs (Feldname: date, im Format d.m.Y – Wenn keine Jahreszahl bekannt ist, nimm das aktuelle Jahr.),
  • Die Gesamtsumme (Feldname: total_sum),
  • Die Namen des Geschäfts (Feldname: store_name),
  • Eine Liste der Produkte, mit folgenden Unterfeldern: (Feldname: items)
    • Name (Feldname: name)
    • Geratener Vollständiger Langer name, falls der Name nur ein Kürzel ist (Feldname: long_name)
    • Preis (Feldname: amount, in Euro-Cents)

Dankeschön!

Was soll ich sagen — es funktioniert eigentlich ziemlich gut. Er schafft es ziemlich gut, sich plausible Sachen auszudenken, sodass der Bon fast benutzbar wird. Ich erwarte hier ja auch gar keine Perfektion, mir reicht, wenn es halbwegs Sinn ergibt. Im Zweifelsfall kann man ja immer noch den Scan direkt angucken.

kassenbon_json.png
Ausschnitt aus dem Ergebnis. “Spachtelstift” ist eigentlich “Spachtel, steif”, aber nun gut.

Drei Nachteile gibt es allerdings noch:

  • Es dauert relativ lange, also mehrere Sekunden, aber das ist man ja von ChatGPT gewohnt.
  • Es kostet pro Kassenbon so 3 - 5 Cent.
  • Manchmal kommen auch kuriose Antworten wie “Ich kann das leider nicht verarbeiten, weil da personenbezogene Daten drin sind”, oder er kennt einfach gar nichts. Im nächsten Anlauf funktioniert es aber. Der Geist in der Maschine!
Nach diesem geglückten Versuch, probierte ich später noch, ob er meinen Tisch mit Canasta-Karten zählen kann, aber das scheiterte leider kläglich. Muss also manuell weiterzählen. Schlimm.

Nach meinem kurzen Test baute ich es als Feature also in meine neue App ein. Die heißt natürlich Serenity, weil es zu Firefly passt und auch der viel bessere Name für so ein Tool ist als Firefly… DREI.

]]>
<![CDATA[Gute Lieder in März 2024]]> https://knuspermagier.de/posts/2024/gute-lieder-in-m-rz-2024 Sat, 16 Mar 2024 23:10:00 +0100 https://knuspermagier.de/posts/2024/gute-lieder-in-m-rz-2024

Ich habe mal wieder ein paar schöne Dinge auf Youtube entdeckt!
Hier eine umfassende Liste von Videos, die ich in den letzten Monaten sehr genossen habe, in umgekehrter zeitlicher Reihenfolge, da ich meinen Youtube-Verlauf von oben nach unten durchgangen bin:

Am Ende des Jahres muss ich mich auf jeden Fall nicht fragen, warum mein Spotify Wrapped mal wieder eine noch geringere Zahl an Minuten ausspucken wird…

]]>
<![CDATA[Dinge, die mich aktuell an Swift und SwiftUI nerven (und teilweise Lösungen)]]> https://knuspermagier.de/posts/2024/dinge-die-mich-aktuell-an-swift-und-swiftui-nerven-und-teilweise-l-sungen Mon, 26 Feb 2024 14:25:00 +0100 https://knuspermagier.de/posts/2024/dinge-die-mich-aktuell-an-swift-und-swiftui-nerven-und-teilweise-l-sungen

Gerade baue ich mal wieder ein bisschen an der Tagebuch-App, da ich sie, seitdem sie eine Swift-App ist, tatsächlich gerne benutze. Ich versuche also das ein oder andere, was die Webapp schon kann nachzurüsten und komme auch langsam voran, aber manche Dinge nerven mich aktuell schon ein bisschen:

Xcode gibt mir kein wohliges Gefühl mehr

Damals, als ich noch beruflich Objective C schrieb und mich sehr viel in Xcode aufgehalten habe, fand ich, dass es der beste Editor ist. Mittlerweile hat sich einiges getan und ich lebe quasi in PhpStorm. Jede Berührung mit Xcode tut seitdem ein bisschen weh, da es langsam ist, die Code Completion immer noch blöd ist und es sich teilweise dumm verhält. Außerdem gibt es kein automatisches Code-Formatting.

Ja, es gibt mit Ctrl + I das automatische re-indent, aber gefühlt geht das nicht so weit, wie das Formatting in PhpStorm und man muss vorher den Code markieren

Folgendes kann man tun um dem etwas entgegen zu wirken:

  • Im Theme die Font zu Jetbrains Mono wechseln, dann sieht es immerhin etwas bekannter aus.
  • SwiftFormat installieren. Damit erhält man ein tolles Tool, das einem die Dateien vernünftig formatiert, einrückt und sogar ein paar Fehler automatisch fixt. Ich hab mir Format File auf den gleichen Shortcut gelegt wie in PhpStorm.

Das “Live-Preview” ist nett gemeint, aber ziemlich unbrauchbar

Wenn man SwiftUI-Views baut, hat man rechts so ein Fenster, das einem Live alles anzeigt, damit man direkt sieht, was man da gebaut hat. An sich toll, auf der anderen Seite stürzt es bei mir öfter ab und braucht um die dreißig Sekunden, bis es wieder läuft. Oder, es pausiert wegen eines Syntaxfehler und wenn ich es ent-pausiere läd es wieder für dreißig Sekunden. Ich habe ein sehr teures Macbook mit einem sehr schnellen M1-Prozessor, das könnte alles schneller gehen.

screenshot-2024-02-26-at-14.30.09.png
Typische Ansicht des Preview-Fensters

SwiftData ist cool aber auch etwas beschränkend

Ich habe wirklich keine Lust jetzt etwas anderes zu lernen als SwiftData, aber dieser ganze Quatsch mit den #Predicate-Dingern, die irgendwie vom Compiler übersetzt werden sorgt dafür, dass ein paar Sachen noch nicht vernünftig gehen, weil in der Closure vom Predicate nur wenige Anweisungen erlaubt sind. Hier und da wünschte ich mir, ich könnte einfach SQL-Queries (bzw WHERE-Conditions) schnell selber tippen, statt sie in das Predicate-Konzept zu quetschen.

Für den “Alle Beiträge am gleichen Tag, aber in verschiedenen Jahren”-View muss ich z.B. schauen, ob der Monat und der Tag vom Erstellungsdatum der Einträge dem heutigen entsprechen. Man könnte also hoffen, dass man sowas gehen würde:

#Predicate<Item> { item in
    Calendar.current.dateComponents([.month, .day], from: item.timestamp) == dateComponentsNachDenenIchSuche
}

Geht aber nicht, da ich die Funktion in dem Predicate nicht aufrufen kann. Ich hab leider nach zehn Minuten googeln keine Lösung gefunden und speichere nun beim Erstellen der Einträge halt noch das Datum als MM-dd extra ab um danach zu selektieren.

Im Vergleich dazu, kann ich im Backend ja einfach folgendes machen:

$query->whereRaw('strftime("%m-%d", date) = ?', $filter['day-of-year']);

Ja, ich weiß, wahrscheinlich liegt es auch einfach daran, dass das hart unperformant ist, wenn man eine Million Tagebucheinträge hat. Jedes mal irgendeine Funktion aufrufen sorgt natürlich dafür, dass die Query einen Full Table Scan machen muss und nicht auf einen Index zurückgreifen kann, von daher ist es wahrscheinlich gar nicht dumm, hier vorzeitig zu optimieren

Versions-Wirrwarr

Es ist weiterhin so, dass sich zwischen den Swift-Versionen so viel getan hat und die Stack Overflow-Antworten teilweise uralt sind. Die Guten wurden irgendwann geupdated und sehen dann so aus:


UPDATE 3: Swift 6
[…]

UPDATE 2: Swift 3 - 5
[…]

UPDATE: Swift 2
[…]

Swift 1:
[…]


Viele aber auch nicht. ChatGPT ist ja leider auch schon etwas älter und liefert daher oft Code aus, der in aktuellem Swift einfach nicht mehr funktioniert. Leider konnte ich die ChatGPT-Dinger, die extra auf die aktuelle Doku trainiert wurden noch nicht testen, das sind glaub ich so custom GPTs, die man nur in der Bezahlversion bekommt? Hat das mal jemand getestet?

Xcode hat kein Copilot

Damit verbunden: Xcode hat kein Github Copilot-Ding. Seeehr nervig. Wobei ich auch nicht weiß, wie gut der Copilot wäre, vielleicht würde er an dem gleichen Problem scheitern, wie ChatGPT?

(Es gibt zwar so ein Projekt auf Github, das ist mir aber nicht ganz geheuer)

Der async/await-Support ist lückenhaft

Weiter kleine Nervigkeit: Noch nicht alle Apple Frameworks haben support für async/await, was ziemlich nervig ist, wenn man z.B. kurz mal ein paar Reminder mit EventKit rauspulen will. Schön wieder completionBlocks, nee, nee!

Fazit

Man muss schon sagen, dass das aktuell mein erfolgreichstes Abtauchen in die SwiftUI-Welt ist. Die App funktioniert gut, ich nutze sie täglich und ich bekomme es halbwegs schnell hin neue Features einzubauen.

Der größte Spaß kommt allerdings eher beim benutzen der App und weniger beim Entwickeln, weil ich ständig anecke, irgendwo warten muss, oder mich durch verwirrende Stack Overflow-Posts wurschteln muss. Letzteres wird natürlich irgendwann wegfallen, wenn ich genug Erfahrung habe und einfach alles weiß, aber bis dahin ist sicher auch schon Swift 8 und 9 raus und alles geht von vorne los!

Ich bin bei Sideprojects ein großer Quick’n’Dirty-Verfechter. Ich habe keine Lust hier Stunden zu verbringen um eine App, die nur ich benutze, perfekt zu optimieren und fehlerfrei zu bauen. Mit den ganzen Web-Technologien funktioniert das supergut, mit Laravel baue ich in wenigen Stunden alles, was ich brauchen könnte als Prototyp zusammen. In Swift bin ich was das angeht leider (noch) sehr langsam, was mich tierisch nervt. Aber das ist eher ein persönliches Problem.

Immerhin fühlt sich das Ergebnis, eine native App, am Ende so gut an, dass es mich genug motiviert, weiter zu bauen und weiter SwiftUI zu lernen, dass meine fehlende Erfahrung zumindest nicht mehr der Roadblock ist.

]]>
<![CDATA[Google Sheets als Datenbasis]]> https://knuspermagier.de/posts/2024/google-sheets-als-datenbasis Tue, 20 Feb 2024 10:35:00 +0100 https://knuspermagier.de/posts/2024/google-sheets-als-datenbasis

Im Wiki gibt es jetzt eine Seite auf der ich unsere Everdell-Spielergebnisse in einer kurzen Statistik präsentiere. Doch woher kommen die Daten dafür? Aufmerksame Leser:innen wissen jetzt schon Bescheid!

Natürlich habe ich keine Lust, die Punktzahlen hier im Kirby in zu pflegen, sowas gehört natürlich in ein Spreadsheet, damit man da wichtige wissenschaftliche Auswertungen fahren kann. Glücklickerweise hat Google Sheets ein tolles “Im Web veröffentlichen”-Feature mit dem man eine Tabelle über einen Link teilen kann, und zwar in verschiedenen Formaten, unter anderem als CSV! Das Beste: Die CSV aktualisiert sich regelmäßig, wenn man etwas am Sheet ändert.

step1.png
Hier klicken…
step2.png
…und fertig!

Der everdell-results-Block vom Wiki schnappt sich also einfach die CSV-Datei, läd sie herunter und zeigt die Daten schick an! Juchu!

(Diesen Trick hat mir mal ein Kollege aus meiner damaligen Firma gezeigt, danke Micha!)

]]>