Schon bevor mein letzter Beitrag zur Commodore 64 Reihe online war, hatte ich schon einige mit meinem Retrofieber angesteckt. Zumindest in der Theorie. Denn man unterhält sich ja und dabei kommt zwangsläufig auf den Tisch womit man sich derzeit beschäftigt. Unter anderem ging es um den
Commodore 16
Das Modell war auch mal in meinem Besitz. Um 1985 kaufte ein Bekannter meines Vaters den Rechner, nutzte ihn jedoch nicht, sodass er irgendwann bei uns landete. Optisch war das Teil auch schick. Hab ich schon erwähnt das mir der Brotkasten sehr gut gefallen hat?!
Der C16 war nicht kompatibel mit dem C64. Zudem hingen die Ports beim 64er ungeschützt direkt an den Chips was ihn extrem anfällig für ESD-Schäden machte, wogegen der 16er unempfindlicher konstruiert wurde. Genau das machte ihn für mich zum perfekten Bastel-Objekt und er landete im Keller. Zum einen war wie erwähnt die Hardware robust, und zum anderen war die Syntax des Commodore BASIC die selbe. Wenn gleich die Speicheradressen zumeist andere waren wodurch man PEEK und POKE nicht eins zu eins übernehmen konnte. Commodore BASIC 3.5 hatte allerdings einige Neuerungen die recht gut waren. Man konnte beispielsweise einzelne Programmzielen anzeigen lassen mit LIST 250. Oder einen kompletten Abschnitt mit LIST 250-350. Mit RENUMBER konnte man neu in 10er Schritten durchnummerieren lassen. Zudem hat er mit dem TED einen neuen Chip bekommen der zu den 16 Grundfarben auch 8 Helligkeitsstufen pro Farbe konnte. Abzüglich 8x Schwarz und noch 8x Schwarz konnte er 112 Farben gleichzeitig darstellen. Und er besaß zwei Tonkanäle. Obwohl der 16er keine echte Bit-Samplerate besaß, nutzten Programmierer einen Trick: Sie steuerten das 8-stufige Lautstärkeregister im TED extrem schnell über CPU-Interrupts an (z. B. mit 4 kHz oder 8 kHz). Durch das schnelle Ändern konnte man eine Art 4-Bit-PCM-Audio erzwingen – das klang zwar etwas rauschig, spielte aber echte Sprache oder Musik ab. Damit war Commodore damals dem x86 um Jahre voraus.
1989 nahm unsere Hauptschule unter der Leitung von Lothar Waigand an dem Projekt „Informatik an Hauptschulen“ des Bayerischen Staatsministeriums für Unterricht und Kultus teil. Lothar, unser Lehrer meldete die Schüler an dem Wettbewerb zu diesem Projekt an. Dazu musste man sich ein Programm überlegen welches man in der Schule schreiben musste und welches dann eingereicht wurde. Ich hatte mein Programm zuhause unter Commodore Basic 3.5 vorbereitet.
Nun war es leider so, das Commodore Basic nicht ganz das selbe war wie GW-Basic welches wir in der Schule verwendet haben, wenn gleich die Basis beider aus der Hand von Bill Gates stammt. Vor allem aber gab es unter VGA nur 16 Farben von denen nur 8 für den Hintergrund zur Verfügung standen. Also habe ich in der Schule das Programm so umgebaut, das nicht die Helligkeit sondern die Farben durchgezählt wurden.
Die Commodore Version hatte potential für den ersten Platz, aber so hat es leider nur für den zweiten gereicht. 😉
Commodore 128
Das Zweite Thema war der Commodore 128.
In unserer Unterhaltung ging es speziell um das Modell 128D. Damals ein wichtiger Unterschied 🙂 Da kaum Spiele speziell für den 128er entwickelt wurden, haben die meisten Besitzer diesen in der Praxis fast ausschließlich als einen etwas moderneren, schickeren 64er genutzt. Da im inneren des C128 die Komplette Hardware vorhanden war die auch der C64 hatte, konnte man den 128er im C64-„Modus“ laufen lassen. Dazu gab es drei Möglichkeiten:
Automatisch über ein Cartridge Modul
Durch drücken der Commodore Taste beim Einschalten (Beim BMC64 Emulator je nach Tastaturlayout und Belegung z.B. SHIFT)
Durch Eingeben des Befehls GO 64
Da der 128er erst um 1986 auf den Markt kam war dieser außer bei meinem Nachbarn für mich kein Thema. Zwei Jahre später war bereits der Commodore Amiga 500/2000 am kommen.
Technische Daten:
Prozessor: MOS8502 – 2 MHz, Zilog Z80 4 MHz
Speicher: 128 KB RAM
Betriebssystem: Basic 7.0, CP/M Plus
Auflösung: 640×200 bei 112 Farben
Allerdings finde ich zwei Dinge doch recht beachtlich. Zum einen hatte der 128er bereits einen Nummernblock, und zum anderen ist die Ähnlichkeit zwischen Commodore 128 und Amiga 500 frappierend.
Ebenso sieht es beim 128D/128DCR aus, der bereits ein Desktop-Gehäuse hatte und dem Amiga 2000 ziemlich ähnlich sieht nur ein bisschen flacher.
Wer noch interessante Anmerkungen oder Geschichten zur Commodore Ära hat, immer her damit.
Last but not least habe ich für Interessiertehiernoch ein paar nützliche Dateien wie Beispielsweise die Pinouts oder ROMs zum Download bereitgestellt.
So, Finger aus der Hosentasche. Jetzt gehts ans Eingemachte. Ich bin dermaßen im Retrotunnel. Commodore is a helluva drug!
ACHTUNG: Das folgende ist übelstes Nerd Zeug! Aber keine Sorge, ganz unten kommen ein paar Bilder, die könnt ihr euch anschauen 😉
Für das intensive Retro Feeling wollte ich meinen Akustikkoppler wieder zum pfeifen bringen. Wie bereits beschrieben findet man heute keine Bulletin Board Systems (BBS) mehr. Aus diesem Grund habe ich nach einer Alternative für das Terminalprogramm gesucht. Nach einigem Grübeln wollte ich es nutzen wozu man auch heute noch Terminalprogramme verwendet. Nämlich Remote per SSH mit einem Linux Server arbeiten. Dazu habe ich mir im Groben folgende Verbindungskette überlegt.
Über den C64-Emulator das Terminalprogramm CCGMS starten.
Von dort über eine virtuelle serielle Brücke auf dem Raspberry Pi zugreifen.
Weiter über einen USB zu Seriell Wandler zu meinem Dataphone s21-23d/64.
Dort ein echtes analoges Telefon auflegen und über die analoge Telefonleitung weiter.
Ein SLIC-Modul zur Simulation des Telefonnetzes verwenden.
Und von da über einen ESP32 via WLAN und SSH auf den Debian-Server.
Schien machbar zu sein. Also los geht es, aber nicht in dieser Reihenfolge.
Installation und Konfiguration von socat
Der wichtigste Baustein auf meinem Weg war ein kleines Tool namens socat welches die unterschiedlichsten Pipes erzeugen kann. Installiert wird das wie folgt:
Bash:
sudo apt update
sudo apt install socat -y
Danach kann man eine virtuelle serielle Schnittstelle /tmp/vtty0 erzeugen die später eine Pipe zu /dev/ttyUSB0 erzeugt. Nach dem starten mit
läuft das Tool zunächst mit einer Pipe zur lokalen Bash, und man muss zum Testen in einer anderen bash weiterarbeiten. Achtung beim Nachbauen, denn je nach Anwendungsfall und Aufrufparameter wird die Pipe gekillt, wenn eine etablierte Verbindung einseitig geschlossen wird. In einem solchen Fall muss man den Prozess überwachen, und die Pipe automatisiert neu starten, damit sie für die nächste Verbindung zur Verfügung steht. Testen kann man das nun in der zweiten bash mit
indem man socat als Client einsetzt. Da es kein Terminalprogramm ist erscheinen an manchen Stellen gegebenenfalls Steuerzeichen. Darüber muss man sich keine Gedanken machen. Diese werden durch die Verwendung eines echten Terminalprogramms entfernt. Noch ein Tipp: Ich will es nicht verheimlichen! Dieser Punkt hat mich am gesamten Projekt die bei weitem meiste Zeit gekostet, und um ein Haar auch meinen Verstand. Je nach Verbindungstyp wie zum Beispiel Telnet oder SSH reagiert der Server unterschiedlich auf Tastatureingaben und vor allem Zeilenumbrüche, carriage return (CR) oder line feed (LF). Dazu bei Bedarf im Manual folgende Parameter anschauen: isig,icanon,echo,xcase,lnext,noflsh,iexten,brkint,icrnl,inpck,istrip,inlcr,igncr,opost. Wenn beim Test alles passt, keine Treppen oder Leerzeilen entstehen, ist alles richtig eingestellt
so wie hier. Nun können Client so wie Pipe mit STRG + C gekillt werden. Jetzt kommt der wirklich heiße Scheiß. Mit denselben Formatierungsparametern in
werden die seriellen Daten in eine SSH Verschlüsselung gezwungen und über /dev/ttyUSB0 mit 1200 Baud rausgeschoben. Ja, und natürlich auch wieder rein. Leider gibt es hier nun zwei Stolpersteine. Beim ersten Start wird gefragt ob der SSH Fingerprint gespeichert werden soll, was mit „Ja“ erledigt ist. Problematisch ist allerdings, das man zum Angegebenen user@server_ip jedesmal ein Passwort eingeben muss. Bevor man also die socat SSH Pipe durch crontab -e mit dem Eintrag
in den Autostart integriert, fehlen noch ein paar Schritte. Zunächst muss der User auf jedem System vorhanden sein, auf das man sich verbinden will. Des weiteren benötigt man eine SSH-Key-Authentifizierung (oder auch SSH-Schlüsselpaar genannt). Mit
wird das Schlüsselpaar generiert. Bei der Frage nach einer „Passphrase“ einfach Enter drückten, damit der Autostart später nicht nach einem Passwort für den Schlüssel selbst fragt. Mit dem Copy wird der Schlüssel in die Datei ~/.ssh/authorized_keys des Ziel-Users geschreiben. Wenn ssh dort einen passenden Schlüssel findet, lässt es einen ohne Passwort rein. Da hiermit der Generalschlüssel für diesen User vorhanden ist kann man ihn
Bash:
ssh-copy-id user@server_ip
per ssh auch auf die anderen Server kopieren. Der Befehl baut automatisch eine SSH-Verbindung zum Zielsystem auf. Das Prinzip bleibt dasselbe. Die 4096 ist die Schlüssellänge von SSH in Bits. Sicherheitsbedenken? Das Schlüsselpaar steht nur dem User der angegebenen Zieladresse und nur vom lokalen System aus zur Verfügung. Zum testen gibt man folgendes ein:
Bash:
ssh user@server_ip
Wenn man eine neue SSH-Verbindung öffnet, und alles geklappt hat, benötigt man dazu kein Passwort mehr.
FTDI FT232RL & Dataphone s21-23d/64
Als nächstes muss der Akustikkoppler mit einem Userport zu RS232 Adapter verbunden werden, welcher wiederum mit einem RS232 zu USB Adapter verbunden ist, welchen man dann in den Raspberry Pi stecken kann. So zumindest der Plan von meiner KI. Aber irgendwas daran ist doch Faul. Achja, die C64 Hardware hatte damals durch die Bank 5V Schnittstellen. Und somit hatte auch die C64 Version des Dataphones s21-23d/64 eine 5V Schnittstelle. Also nix Standard RS232 Adapter. Bei meinem Fräsenprojekt allerdings hatte ich eine Platine gelötet die man an den USB-Pot stecken konnte. Auf der Platine war der FT232RL-Chip von FTDI verbaut. Dieser Chip ist ein USB-zu-TTL/UART-Wandler, der serielle Signale auf einem 5V-Pegel ausgibt.
Leider gibt es beim Dataphone s21-23d/64 eine weitere Besonderheit zu beachten: Da der Userport des C64 mit invertierten TTL-Pegeln arbeitet, durfte ich die Signale des FTDI-Chips nicht einfach so einspeisen. Ich musste das Dienstprogramm FT_PROG von FTDI wieder rauskramen und den FT232RL so umprogrammieren, dass er die TTL-Signale (RX und TX) hardwareseitig invertiert.
Um die FTDI-Platine mechanisch mit dem Dataphone zu verbinden, habe ich das originale Kabel (das einen speziellen C64-Userport-Stecker hatte) abgezogen. Stattdessen habe ich einen neuen DIN-Stecker verwendet, die Leitungen angelötet und RX, TX sowie Masse (GND) direkt mit den entsprechenden Ausgängen des FTDI-Wandlers verbunden.
Nach einem kurzen Test über socat kam ein lautes, vertrautes Düdeln aus dem Lautsprecher des Dataphone! Scheiße, Gänsehaut…
Detailinformationen über die genaue Funktionsweise der Akustikkoppler und der Datenübertragung über analoges Kabel würde hier den Rahmen sprengen. Einfach mal nach FSK, CCITT, v.21 und v.23 suchen. Somit wäre die eine Seite fertig und Bereit.
Die Brücke ins analoge Telefonnetz
Als nächstes kommt ein altes analoge Siemens Telefon ins Spiel da ich kein grünes Wählscheibentelefon der Post mehr hatte. Wenn man ein Telefon abhebt, erwartet es eine aktive Telefonleitung. Da ich keine Vermittlungsstelle der Post in meinem Keller gefunden habe, musste ich diese selbst bauen. Dazu muss man die typischen Zustände und Spannungen eines klassischen analogen Systems verstehen.
Im Ruhezustand wenn der Hörer aufgelegt ist, liegt eine hohe Gleichspannung von 48-60V DC am Telefon an.
Um das Telefon zum klingeln zu bekommen wird der Gleichspannung eine Wechselspannung aufmoduliert wodurch man stellenweise 90V AC bei 50 Hz auf der Leitung hat.
Hebt man ab (Off-Hook) schließt sich der Stromkreis im Telefon. Die Spannung auf der Leitung bricht durch den Innenwiderstand des Telefons ein was die Vermittlungsstelle erkennt. Diese entfernt die Wechselspannung (Klingeln) wodurch folgend ca. 10V DC auf der Leitung sind.
Wenn ich am Telefon eine Taste drücke, werden durch das IWF (Impulswahlverfahren) eben so viele Impulse erzeugt wie die Nummer die man drückt. Das erkennt die Vermittlungsstelle und wertet diese aus.
Um diese komplexen Aufgaben nicht diskret aufbauen zu müssen, habe ich mir für 3,49€ ein KS0835F SLIC-Modul (Subscriber Line Interface Circuit) bei AliExpress besorgt.
Ein SLIC übernimmt die typischen BORSCHT-Funktionen:
Battery (Speisung des Telefons mit Gleichstrom)
Overvoltage (Schutz vor Überspannungen)
Ringing (Erzeugung des Rufstroms)
Supervision (Überwachung, ob der Hörer abgenommen wurde)
Coding (Zweidraht- zu Vierdraht-Schnittstelle)
Hybrid (Trennung von Sende- und Empfangsaudio)
Testing (Testfunktionen)
Ich habe das Telefon direkt an die Ausgänge (Tip und Ring) des KS0835F angeschlossen. Die Steuersignale für den Gabelkontakt (Switch Hook) habe ich über einen Pegelwandler an den ESP32 übergeben, um die 5V-Signale des SLIC-Moduls auf die 3,3V des ESP32 zu reduzieren. Die Audio-Ein- und Ausgänge des SLIC-Moduls habe ich für den nächsten Schritt vorbereitet.
Signalverarbeitung TCM3105
Um die analogen FSK-Töne der Telefonleitung beziehungsweise des SLIC-Moduls wieder in ein digitales Signal zu verwandeln, benötigt man einen speziellen Modem-IC. Eine moderne Option wäre ein Entwicklungsboard mit dem FX614-Chip gewesen. Ich hatte jedoch kürzlich mein altes BayCom-Modem (das damals für Packet Radio im Amateurfunk genutzt wurde) in der Hand. Auf diesem ist der Klassiker TCM3105 verbaut. Also dachte ich mir: Warum nicht das nutzen? Ich musste das BayCom-Modem nur minimal modifizieren.
Normalerweise klaut sich dieses Modem seine Betriebsspannung parasitär aus den Handshake-Leitungen (wie RTS und DTR) der RS232-Schnittstelle des PCs. Da ich die RS232-Schnittstelle hier nicht nutze, funktionierte das natürlich nicht. Ich habe das Gehäuse geöffnet und kurzerhand drei Drähte direkt an den TCM3105 gelötet, um eine externe +5V-Spannungsversorgung einzuspeisen und die reinen TTL-Pegel (RX und TX) direkt abzugreifen. Diese Signale habe ich auf freie, unbelegte Pins der D-Sub-Buchse des Baycom-Modems herausgeführt.
Pegelwandlung ADUM1401
Da der TCM3105 mit 5V TTL-Pegeln arbeitet, mein ESP32 jedoch nur 3,3V an seinen GPIOs verträgt, musste eine Pegelwandlung her. In meiner Bastelkiste befand sich noch eine Platine mit einem ADUM1401 die ich als Testplatine für meinen Slotcar Tisch angefertigt hatte. Das ist ein digitaler Isolator, der nicht nur die Pegel sauber zwischen der 5V und der 3,3V Seite umsetzt, sondern die beiden Systeme auch galvanisch trennt. Da der 1401 drei Vor- und einen Rückkanal hat, ich aber wegen der „+5V“ Switch Hook Leitung zwei Rückkanäle brauchte musste ich die Richtung wechseln weshalb ich den 5V DAC für die Tests entfernen musste.
ESP-32 ssh WLAN Bridge
Die 3,3V Signale (RX, TX und das Switch-Hook-Signal vom SLIC) laufen nun im ESP32 zusammen. Die Software, die ich für den ESP32 geschrieben habe soll folgendes machen:
Beim ersten booten spannt der ESP32 ein eigenes WLAN auf über das man die Software Konfigurieren kann.
Danach verbindet sich der ESP32 mit dem eingestellten lokalen WLAN.
Sobald mein eingestellter Linux-Server erreichbar ist, baut der ESP32 im Hintergrund eine SSH-Verbindung dorthin auf.
Sobald die Verbindung steht, wartet das Programm im Hintergrund auf das Signal des Gabelkontakts (Switch Hook).
Wenn ich den Hörer des analogen Telefons abhebe (Switch Hook: aktive) initialisiert sich die UART zum TCM3105.
Das ganze habe ich dann Schrittweise getestet, und jeder dieser Schritte hat für einen erneuten Gänsehaut-Moment gesorgt. Wenn man den Telefonhörer abhebt und hört das klassische leise rauschen der Telefonleitung.
Und dann initialisiert man die UART Schnittstelle im ESP32. Die TX Leitung ist dann im Leerlauf immer auf Logisch-HIGH. Sobald der TCM3105 die 1 sieht, erzeugt dieser die typischen 1200 Hz womit das Carrier Signal steht. Aus der Hörmuschel kommt das typische monotone pfeifen der Gegenstelle. Yes!!! Sobald man sich wieder einigermaßen im Griff hat, kann man den Hörer auf die Gummipads des Akustikkopplers drücken und schonmal den nächsten Test mit socat machen.
CCGMS unter Commodore 64
Jetzt wird es knifflig. Zunächst muss ich erwähnen das ich an dieser Stelle auf die stand allone Version von VICE umstellen musste da unter Emulationstation hier wichtige Funktionen nicht mitinstalliert werden. Dann habe ich mit dem CCGMS 2021 Fork von Alwyz gestartet, weil ich zunächst das Original nicht gefunden habe.
VICE starten und CCGMS laden.
Mit F12 das VICE Menü öffnen
Settings -> Peripheral devices -> RS232 settings
Userport RS232 emulation aktivieren
Device 1 auf /tmp/vtty0 setzen
Zurück zu CCGMS
Mit F7 Modem Parameter setzen
Mit M das Modem auf Userport stellen
Mit B die Baudrate auf 1200
Mit S kann man die Einstellungen speichern
Mit F8 den Zeichensatz von PETSCII auf ASCII umstellen
Wichtig ist, den Device nicht auf /dev/ttyUSB0 zu setzen. Da erreicht man zwar auch den Akustikkoppler, aber ohne den SSH Tunnel. Wenn alles richtig eingestellt ist kann man traditionell mit CONNECT 1200 den Device 1 öffnen
und einmal ENTER drücken. Und was soll ich sagen? Bin ich schon drin oder was?
Es hat alles funktioniert so als würde man direkt vor PuTTY sitzen, während das Dataphone vor sich hingedüdelt hat wie damals. Allerdings hat mich doch überrascht das die Farben so perfekt gepasst haben. Und je mehr ich mich damit beschäftigt habe, desto klarer wurde mir: Ich war nicht der Erste mit dieser Idee. Alwyz hatte viele zusätzliche Funktionen bereits fest in seinen modernisierten Fork integriert. Das war im ersten Moment ein echter Dämpfer, denn auch VICE wurde dahin gehend ergänzt die Schnittstelle ins Internet zur Verfügung zu stellen. Ich wollte aber keine aufpolierte, moderne Komfort-Software auf dem C64, die mir die Arbeit abnimmt – ich wollte das Original von damals! Also Rolle rückwärts. Nach längerer Suche habe ich dann das Original von 1984 in der Version 4.0 von Craig Smith gefunden.
Auch hier das selbe Vorgehen, aber zunächst wie damals den Hintergrund auf weiß und die Schriftfarbe auf Grau stellen. Das Farbschema sowie die geänderten Verbindungseinstellungen „S“peichern. Mit CONNECT 1200 den Device 1 öffnen.
Und siehe da, ein Träumchen. Da war er wieder, der Retro Tunnel
Noch was zu den Farben und dem Protokoll der Terminalkommunikation. Es heißt ja CCGMS (Commodore Color Graphics Manipulation System). Da ich nicht verstanden habe warum es zwar nicht perfekt funktioniert, aber trotzdem Farbunterschiede vorhanden sind muste ich mich intensiver damit Beschäftigen. Die Erfinder des ANSI-Standards (offiziell ECMA-48 bzw. ISO/IEC 6429) haben sich für die Terminals und Konsolen ein System ausgedacht, das man als Steuerung mit Escape-Sequenzen bezeichnet. Dabei ist der Teil der Textformatierung im Bereich SGR (Select Graphic Rendition) definiert. Anschauen kann man sich das in der ANSI-SGR-Tabelle. Zunächst zu den Farben: Auf dem Commodore 64 kann man im CCGMS seine eigenen Farben einstellen. Mit ctrl + B schaltet man die Hintergrundfarben hintereinander durch. Mit ctrl + 1..8 wählt man die ersten 8 Farben als Schriftfarbe aus. Mit C= +1..8 wählt man die nächsten 8 Farben als Schriftfarbe aus. Im VICE Emulator kommt es auf das Keybordmapping an. Ich habe mir die CTRL Taste auf STRG und die C= Taste auf TABULATOR gelegt. Die Farben der Escape Sequenzen allerdings kann man nicht verstellen. So wie ein Sys-Op sein BBS erstellt hat, exakt so sollte es ja dargestellt werden. Das kann man sich wie bei einer modernen Website vorstellen. Da wird die Schriftfarbe beispielsweise auch mit #FF0000 „rot“ vorgegeben, und der Browser bietet keine Option diese Schriftfarbe immer als #00FF00 „grün“ anzuzeigen. Soweit hoffentlich verständlich. Nun zum System der Escape Sequenzen.
Escape String:
\x1b[32m
Die Farbeinstellung in der Konsole wird traditionell durch Escape ‚\x1b[‚ eingeleitet, gefolgt von einer oder mehreren durch ; getrennte SGR Nummern. Der Abschluss für SGR erfolgt durch den Terminator ‚m‘. Dazu haben die Entwickler des Standards zu der damaligen Zeit die SGR-Nummer in Zehnerblöcke aufgeteilt, mit viel Platz für Reserven. 0 – 9 beispielsweise waren die „Stile“ wobei die 0 für „Reset“ steht. 30-39 war die erste „Bank“ der Farbpalette wobei 38 & 39 unbelegt war. 40-47 war die erste „Bank“ der Hintergrundfarbe Da zum Zeitpunkt der Entwicklung des Standards nur mit einer 8 Farben Palette zu rechnen war, wurde die 30-37 für diese ersten 8 Vordergrundfarben reserviert. Später kam für die zweite „Bank“ die 90-97 für die „Hellen“ Vordergrundfarben dazu. Beim Commodore VIC-II sah die Farbpalette etwas anders aus.
Das Prinzip war aber das gleiche. Mit \x1b[7;32;41m beispielsweise stellte man die Textfarbe auf grün, die Hintergrundfarbe auf rot sowie den Text invertiert dar. Mit \x1b[0m stellte man es auf die „Standardfarben“ zurück. Schaut man sich das beim C64 an, ist die 32 der Index $02 mit der Farbe rot. Die 41 hatte den Index $01also weiß, und die 7 hat den Text invertiert dargestellt. Heute schaut das ganze nun beispielsweise so aus:
Escape String:
\x1b[38;2;255;0;0m
Die 38 die früher Reserve war besagt, es soll die Vordergrundfarbe detailiert eingestellt werden. Die 2 besagt, verwende den 24-Bit RGB Modus, gefolgt von den RGB Werten 255;0;0 also #FF0000. Das Escape und der Terminator ist unverändert geblieben. Warum ist es aber so, das der Interpreter des Terminalprogramms für diverse Farben der modernen Konsolen bei mir ein dunkles Grau verwendet? Zunächst dachte ich, die 38 ist der VIC-II Index $08. Das hätte vom Verhalten her alles erklärt. Nur leider wäre das Orange gewesen. Craig Smith allerdings war damals schon so weitsichtig, das er ein Emergency Fallback eingebaut hat. Er hat nämlich einprogrammiert, das bei unbekannten Nummern der Index $0C verwendet werden soll, was eben das Dunkelgrau der zweiten „Bank“ ist. Das heißt also, sobald irgend eine moderne Farbe (38) eingestellt werden soll, fällt des CCGMS auf die Dunkelgrau zurück, und wird durch die 0m auf die Standardfarben zurückgesetzt. Funktioniert also perfekt auch mit modernen Escape Sequenzen.
Mein Ziel ist erreicht – und wie! Der Akustikkoppler tüftelt vor sich hin und der Prompt der Linux-Bash blinkt auf dem C64-Bildschirm. Gänsehaut pur. Ohne Abkürzung moderne Linux-Server steuern mit dem Sound, dem Look und dem unschlagbaren Vibe der 1980er Jahre. Es ist laut, es ist langsam, es ist vollkommen verrückt. Und genau deshalb liebe ich mein Hobby!
C64 goes Internet
Der Vollständigkeit halber! Wie oben bereits erwähnt, wurde VICE dahingehend erweitert, das man auf einen Lokalen TCP Port zugreifen kann, ohne groß Klimmzüge machen zu müssen. Deshalb möchte ich hier eine Aussage die ich in dieser Artikelserie getätigt habe zurücknehmen. Denn es gibt tatsächlich noch/wieder aktive Bulletin Board Systeme oder heute besser Bulletin Board Server. Man könnte über
eine Verbindung zu einem BBS herstellen, und diese dann unter VICE nutzen. Die einfachste Methode ist allerdings das Tool tcpser. Dieses emuliert ein Modem auf einem lokalen Port das alles mitbringt inklusive ATDT.
Bash:
git clone https://github.com/FozzTexx/tcpser.git
cd tcpser
make
Nach der Installation startet man das Tool wie folgt.
Bash:
tcpser -v 25232 -p 23 -s 38400
Damit lauscht es intern auf dem Port 25232, und extern auf dem Port 23 (Telnet) falls man selbst ein BBS stellen will. Da es das damals so nicht gab, muss man auch nicht auf Authentizität achten. Deshalb können wir „für einen 64er“ ordentlich Gas geben, und die Verbindungsgeschwindigkeit auf 38400 Baud stellen. Alternativ 1200 wer es klassisch will. Unter Vice aktiviert man nun die ACIA Emulation auf $DE00 und einem Device seiner Wahl, dem Ziel 127.0.0.1:25232 und 38400 Baud. Danach CCGMS 2021 wie folgt einstellen
und mit RETURN bestätigen. Nun kann man mit ATDT server:Port ein BBS seiner Wahl „anrufen“.
CCGMS:
ATDT 8bit.hoyvision.com:6400
Ein großes Lob an die Community, die BBS ins Internet-Zeitalter gerettet hat! Es läuft gut, macht auch eine gewisse Zeit Spaß. Allerdings ist der Informationsgehalt wie früher ehr dürftig. Und so spannend diese Brücke zwischen den Welten ist: Für einen Romantiker wie mich fehlt ohne die analoge Telefonleitung, das klassische pfeifen, und alles drum herum schlicht das Herzstück des damaligen Erlebnisses. Es ist faszinierend, aber für mich nicht authentisch.
Ich hoffen ich konnte euch mit meinem Retrofieber anstecken und hoffe der ein oder andere hatte Spaß beim lesen. Über Anregungen bin ich wie immer Dankbar.
Im zweiten Teil meiner Reihe möchte ich zeigen wie sich die Computertechnik während der Zeit in der ich sie nutze, verändert hat. Ich habe immer wieder den Eindruck das viele die Begriffe kennen aber nicht wirklich wissen was da überhaupt los ist. Hier möchte ich Datenmengen, Datenraten und Rechenleistung greifbar machen und eine Art Vorlage an die Hand geben, wie man diese Begriffe auch Kindern oder digitalen Einsiedlern verdeutlichen kann – gerade dann, wenn die Glasfaserleitung wieder mal zu langsam ist oder das 5G am Handy die Eieruhr rotieren lässt. Da der gesamte Beitrag sonst zu unübersichtlich wird, kann man die Grafischen Darstellungen mit einem klick auf das Blaue Pfeilchen Ein- und wieder Ausblenden.
Die Schlauberger unter euch werden während dem Lesen sagen: „stimmt ja alles nicht“. Zumindest würde ich mir das denken. Da gibt es ja Stopp Bits, Parity, Kompression, Parallel Slowdown, Collision Avoidance, oder gar Protokoll Overhead, und vieles mehr. Ja das stimmt alles aber das geht zu sehr in die Tiefe und das lasse ich bei meinen Darstellungen und Rechungen bewusst weg, und zeige nur die Brutto Daten und Datenraten. Auch sind die Jahres- und Größenangaben keine Wissenschaftlich ermittelten Min, Max oder Mittelwerte, sondern von mir geschätzte Angaben. Also los gehts…
Speicherkapazität
Digital kommt vom Wort „digitus“ was Finger heißt. Da Menschen seit jeher mit den Fingern Zählen entstand daraus im englischen der Begriff Digital, für Ziffer. Im Digitalen werden Informationen in exakte, einzelne Werte zerlegt. Die Grundlage für frühe Rechenmaschinen und Computer ist das Binärsystem. 1 oder 0, Strom fließt oder nicht. Das ist die Basis und nennt sich Bit. Die nächst größere Einheit nennt sich Byte. In der Pionierzeit der Computer war die Größe eines Byte variabel und konnte aus 3 bis 12 Bit bestehen. Erst durch IBM wurde in den 1960ern der Standard von 8 parallelen Datenleitungen etabliert, da IBM damals den Markt beherrschte. Die Entwickler überlegten wie viele verschiedene Zeichen man darstellen will, und haben sich auf 256 geeinigt also 8 Bit.
Da Computer im Binärsystem (Basis 2) rechnen, passt der Teiler nicht beim SI-Präfix 1000, sondern bei 1024 und nennt sich dadurch IEC-Präfix. Demnach ist ein Kilobyte 1024 Byte groß. Die Schreibweise der Einheiten ist im Internet eine wilde Mischung. Hier kommen Kilobyte, KB, kByte, KiB und viele mehr zum Einsatz. Mein erstes Speichermedium mit dem ich gearbeitet habe, war die Datasette. Auf 30 Minuten Band passten 100 kByte was 102.400 Zeichen/Buchstaben entspricht. Zur Einordnung: Ein durchschnittlicher Krimi/Thriller hat ~170.000 Buchstaben.
Jahr
Medium
Speicherplatz
Details / Schnittstelle
1983
Datasette
100 kByte
100 kByte a 30 Minuten Band
1984
5¼“ Diskette
166 kByte
166 kByte pro Seite
Somit passen auf eine Seite einer 5¼“ Diskette 169.984 Zeichen.
Hier die visuelle Darstellung wie viele Zeichen auf eine 5¼“ Diskette passen:
Jahr
Medium
Speicherplatz
Details / Schnittstelle
1987
3½“ Diskette
720 kByte
z.B. Amiga
1987
MFM-Festplatte
20 MB’yte‘
Zorro II Bus – Commodore Amiga ISA Bus Einsteckkarte – x86 PC
1990
3½“ Diskette
1,44 MB
x86 PC
1990
ATA-Festplatte
40 MB
ISA Bus Einsteckkarte – x86 PC
1991
SCSI-Festplatte
100 MB
ISA Bus Einsteckkarte – Industrie Standard
1998
CD ROM
650 MB
CD RW mit bis zu 700 MB
2000
Ultra ATA/PATA
30 GB
PCI Einsteckkarte oder OnBoard – x86 PC
2003
DVD RW
4,7 GB
Unterschiedliche Standards
Auf eine DVD passen 29.688 5¼“ Disketten
Hier die visuelle Darstellung wie viele 5¼“ Disketten auf eine DVD passen:
Jahr
Medium
Speicherplatz
Details / Schnittstelle
2004
SATA
200 GB
PCI Einsteckkarte oder OnBoard
2006
BlueRay
25 GB
BlueRay RW mit bis zu 75 GB
2006
SATA II
400 GB
PCI Einsteckkarte oder OnBoard
2025
M.2 SSD
4 TB
Multi Layer Cell Solid State
2026
SATA III / SAS 4
44 TB
HAMR Mozaic 4+
Hier sei angemerkt, das solche Festplatten aktuell für Rechenzentren gebaut werden und weniger für den Heimanwender.
Hier eine visuelle Darstellung wie viele DVDs auf eine Exos 44 TB passen:
Es ist also interessnat wie verschwenderisch wir seit langer Zeit mit Speicherplatz umgehen.
Datentransferraten
Kommen wir zum nächsten Punkt, und zwar wie schnell Daten von A nach B kommen. Mit welcher Technologie das gemacht wird ist erst mal egal. Die App liegt im App-Store und soll aufs Handy. Die Daten liegen im Speicher und müssen zur CPU.
Jeder der mit IT etwas zu tun hat sollte es kennen: Wargames! Wenn nicht das Buch, dann den Film. David Lightman dringt mit seinem überragenden IMSAI 8080 in einen Militärischen Supercomputer ein, und startet dadurch versehentlich den Weltweiten Thermonuklearen Krieg. Hat mich sehr in den Bann gezogen. Wargames das Buch hat 24047 Worte welche zumeist durch ein Leerzeichen getrennt werden. Im deutschen hat ein Wort durchschnittlich 6 Buchstaben, wobei wir mit Leerzeichen bei 7 sind.. Somit hat das Buch 168329 Buchstaben und passt gerade so, wenn nicht perfekt auf eine 5¼“ Diskette. Dieses Buch ist nun unsere Basis.
Zugegeben, ich hatte zunächst mehrere andere Bücher im Sinn. Zum Beispiel Colossus von D. F. Jones oder Nineteen Eighty-Four (1984) von George Orwell. Die hatten aber knapp über 300.000 Buchstaben, weshalb sie zwar auf eine 5¼“ Diskette gepasst hätten, aber nur mit Diskettenlocher und das hätte meine Rechnung verfälscht. Also hab ich geschaut und bin im Keller auf das Buch Wargames gestoßen. Das war ein sogenanntes „Movie Tie-in“. Bedeutet basierend auf dem Drehbuch geschrieben, und diese sind zwangsläufig ehr kürzer. Also gehen wir damit ins Rennen.
Jahr
Verbindung
Datenrate
Details
1983
Cassette Port
800 Bit/s
300 Baud – Pulse Length Encoding Datasette
1983
User Port
960 Bit/s
1200 Baud – 8N1 z.B. Akustikkoppler
1983
Commodore Serial Bus
3,2 kBit/s
IEC-Bus Diskette
1996
ISDN
64 kBit/s
pro Kanal, max 128 kBit/s
2000
DSL
768 kBit/s
Asynchron
2004
DSL 2000
2000 kBit/s
Option zu FastPath
Um im Jahr 1983 das Buch „Wargames“ in Digitaler Form von einem BBS zu laden, hätte man theoretisch 7 Minuten gebraucht. Das ging nicht weil man die Daten nicht schnell genug weg schreiben konnte. Im Jahr 1996 benötigte man dazu noch ca. 21 Sekunden. Im Jahr 2000 waren es noch 1,8 Sekunden und im Jahr 2004 noch 0,66 Sekunden. Bildlich gesprochen: 2004 konnte man gedruckte Bücher gar nicht so schnell aus dem Fenster werfen, wie man sie in digitaler Form heruntergeladen hatte!
Jahr
Verbindung
Datenrate
Details
2006
ADSL2+
16000 kBit/s
2010
VDSL
50000 kBit/s
2026
Glasfaser
1 GBit/s
Fibre to the Home
2026
LAN
2,5 GBit/s
Netzwerk
2026
USB-C
40 GBit/s
Thunderbolt 4 0,8 Sekunden pro Film
Ab 2004 lese ich keine Bücher mehr. Ich schaue nur noch DVD’s, weshalb ich mir den Film kaufen musste. Dazu gab es dann von 20th Century Fox die Option zu einer „Digital Copy“. Der Film hat 114 Minuten Spielzeit wodurch die DVD mit ~3,9 GB nicht ganz voll ist. Um die Sicherheitskopie herunterzuladen benötigte man 2004 circa 4,5 Stunden. 2010 benötigte man 11 Minuten. Wenn wir diese „Digital Copy“ heute mit Gigabit Glasfaser aus dem Netz laden, müssen wir lediglich 32 Sekunden warten. Um das für unser Buch zu übersetzen. Mit Glasfaser kann man jede Sekunde 6317 digitale Kopien vom Buch „Wargames“ herunterladen.
Rechenleistung
Gordon Moore hat während der Anfangszeit der Chipfertigung (Integrated Circuit) bzw integrierten Schaltkreisen bereits 1965 erklärt, das sich die Packungsdichte, oder eben die Anzahl von Transistoren auf einem Wafer innerhalb von 2 Jahren verdoppelt. Das konnte er zu der Zeit eigentlich noch gar nicht belegen, da es schlichtweg keine Vergleichswerte gab. Trotzdem gab ihm die damalige Entwicklung recht, weshalb es später das Mooresche Gesetz (engl. Moore’s Law) genannt wurde. Nach dem die Theorie aufgestellt war, wurde diese ehr zu einer selbsterfüllenden Prophezeiung. Denn es sind verschiedenste Industriezweige an der Entwicklung besserer Mikrochips beteiligt. Diese müssen sich auf gemeinsame Meilensteine einigen und in ihrer Roadmap einplanen. Heute geht man von 18 Monaten aus.
Da die Packungsdichte und die Rechenleistung nur indirekt linear verlaufen, schauen wir uns der Einfachheit halber den MOS 6510 und einen Intel Core i7-14700K im direkten Vergleich an.
MIt der Einheit MIPS (Million Instructions Per Second) wird die Rechenleistung von älteren Prozessoren oder Mikrocontrollern ohne Fließkommaeinheiten gemessen. MIPS misst, wie viele Millionen Befehle ein Prozessor pro Sekunde ausführen kann. Das wäre wohl der fairste Vergleich.
Hier kommt der C64 auf ca 0.4 MIPS
Der Intel kommt auf mickrige 400.000 MIPS
Mit der Einheit FLOPS (Floating Point Operations Per Second) wird die Rechenleistung beim Berechnen von Fließkomma-Zahlen (Dezimalzahlen) gemessen. Da der C64 keine Hardware für Kommazahlen hatte, mussten diese mühsam per Software im BASIC berechnet werden.
Hier kommt der 64er immerhin auf rund 2 kFLOPS
Der Intel hingegen kommt bei Volllast auf wahnwitzige 1.500 GFLOPS
Gewichtet man das, ist eine moderne CPU im logarithmischen Mittelwert 22Millionen Mal schneller als der MOS 6510. Um so beachtlicher ist es was man mit dem 64er damals schon alles machen konnte.
Ich beschäftige mich seit geraumer Zeit damit in meinem Keller aufzuräumen und auszumisten. Die Sachen die ich aufhebe, habe ich bisher in einer Excel Datei aufgelistet, damit ich sie leichter wiederfinde. Es war ein einfacher Ansatz um zu starten, ist allerdings nicht sehr Komfortabel. Weder beim Gruppieren, noch beim Eintragen, und schon gar nicht beim Suchen.
Nach dem Motto: „Excel is NOT a Database“ habe ich mein System nun umgestellt.
Aber von vorne. Für meine Slotracing Website habe ich die erste Version meines CMS (Content Management System) programmiert. Mit meinem Energiedashboard kam eine Domainübergreifende Benutzer und Rechte Verwaltung dazu, und mit meiner digitalen Einkaufsliste kam die AJAX Datenbank Suchfunktion dazu. Des weiteren eine Erkennung des Endgerätes und ein Modul welches die Website als PWA (Progressive Web App) ausgibt damit es sich auf einem Mobile-Device wie eine native App verhält.
Auf dieser Basis habe ich gestern Abend in zwei Stunden mein Lagerverwaltungstool erstellt, was meinen Excel Aufschrieb ersetzt.
Man kann beliebige Lagerorte anlegen und man kann verschiedenste Boxen anlegen welche man einem Lagerort zuweisen kann. Auf der Hauptseite kann man entweder nach einem Schlagwort suchen wobei man während der Eingabe schon Vorschläge bekommt, oder über den Suchbutton eine Liste anzeigen lassen. Alternativ kann man auch über das Dropdown direkt über die Box einsteigen. Oder man beginnt mit einer neuen Box. Auf jeden Fall wird dann der Inhalt der Box angezeigt welchen man Hinzufügen oder Entfernen kann.
Bevor die folgenden Zeilen jemand in den falschen Hals bekommt, möchte ich ausdrücklich darauf hinweisen das ich mir das Gerät bewusst und im vollem Besitz meiner Geistigen Kräfte gekauft habe. Auch möchte ich keinesfalls jemandem einen Vorwurf machen, da ich die von mir benötigten Funktionen vor dem Kauf abgewogen habe. Zugegebener Weise nicht in jeglicher Hinsicht korrekt. Das hat mich in den letzten Wochen stark frustriert was sich in diesem Artikel niederschlägt. Wer mich kennt weiß allerdings dass das letzte was ich tue Aufgeben ist.
Hier hatte ich bereits erwähnt das mir Zendure empfohlen wurde und wie ich geplant hatte diese in meine HomeAutomation einzubinden. Zunächst aber erst mal ein paar Infos um die Zendure Landschaft zu verstehen:
Zendure ist der Hersteller
Zendure SolarFlow ist die Produktkategorie
SolarFlow 1600 AC+ Ist in meinem Fall das Produkt
Hub nennt Zendure seine Steuerungskomponente im Gerät
Zendure Cloud nennt Zendure ihren Hauseigenen MQTT Broker
Nach anfänglicher Euphorie beim Testen meines Proxys mit dem Laptop kamen mir dann doch Bedenken weil ich immer wildere Dinge über die Absicherung des Zendure SolarFlow Hubs und dessen MQTT-Clients gelesen habe. Das war glücklicherweise Grundlos. Als die Kiste kam, habe ich diese über die App in Betrieb genommen und mit dem WLAN des S3-Proxies verbunden. Katsching, sofort hatte ich die SolarFlow auf dem Broker. Super Start dachte ich noch. Pustekuchen. Beim Rumspielen mit den Sollwerten musste ich feststellen, das die Istwerte sich in der App innerhalb 4-10 Sekunden ändern, auf dem MQTT allerdings 16 – 60 Sekunden benötigen. Eine Regeltechnische Katastrophe. Zu diesem Zeitpunkt dachte ich das es eventuell am ESP32 liegt. Also musste eine Alternative her. In der neuesten Firmware kann man nun Praktischerweise einen eigenen MQTT Broker einstellen.
Prima, man öffnet sich den Kunden. Und wieder war mein Gedanke völlig abwegig. Dieser funktioniert nämlich nur dann wenn der intern Voreingestellte mit der Cloud verbunden ist. Keine Verbindung zur Cloud, keine Nachrichten auf dem privaten Brocker. Ok, zum Testen die Kiste ins Internet gelassen, und siehe da …
Enttäuschend. Die selbe Latenz ohne eventuell limitierende Bridge zwischendrin. Daran lag es also nicht. Allerdings kommt auf diesem Weg noch Unmengen an Datenmüll hinzu. Zunächst die Daten des Hubs, der Batterien, und der Off-Grid Steckdose, was den selben Daten im Cloud MQTT entspricht. Das wäre OK, aber zusätzlich Strukturen für Home-Assistant, IO-Broker und was weiß ich noch alles. Und nichts davon konfigurierbar. So geht’s jedenfalls auch nicht.
Nach mühseligen Tagen auf der Suche nach Lösungen bei der mir Gemini und ChatGPT keinen Millimeter geholfen hat, habe ich in einem Forum in dem es um etwas ganz anderes ging das Schlagwort „ZenSDK“ entdeckt. Das ganze Meisterwerk ist, wie soll es denn anders sein, nicht öffentlich Dokumentiert. An dieser Stelle konnte mir Gemini dann weiterhelfen. Denn die GET und POST Anfragen enthalten die selbe JSON Struktur wie bei MQTT. Das ist zwar auch nicht öffentlich Dokumentiert, aber hier hat Reinhard Brandstätter schon reichlich Vorarbeit geleistet. Auf GitHub zu finden unter reinhard-brandstaedter.
In Powershell kurz GET und POST getestet
PowerShell:
Invoke-WebRequest -Method Get -Uri "http://192.168.4.2/properties/report"
Und siehe da, die Istwert Änderung wird sofort angezeigt sobald diese in der App ersichtlich ist wenn nicht sogar schneller. Die SolarFlow also wieder vom Internet getrennt, aber was ist das? Keine Cloud heißt kein API (Application Programming Interface). An dieser Stelle greife ich etwas vor, denn der Hub verbindet sich nicht nur mit dem Zendure MQTT Broker sondern auch mit deren NTP-Server. Und ohne die Zeit schaltet die SolarFlow die Ausgänge nicht frei. Die haben doch nicht mehr alle Latten am Zaun.
Es muss die Frage gestattet sein: Wie steure ich meine „Off-Grid Steckdose“ wenn der Strom weg ist und der Router dadurch keine Internetverbindung mehr herstellen kann. Ach ja richtig, ich kann sie ja vorher schon einschalten wenn ich weiß das gleich ein Stromausfall kommt. Auf die 20 Watt Inverter Leistung im Leerlauf ist ja geschissen.
Also die Solarflow wieder mit dem S3-Proxy verbunden und damit mit meinem Broker. Da geht es dann wieder. Aber nun hatte ich den ganzen MQTT-Müll wieder auf meinem Broker. Der Plan: Erstens den Proxy umbauen, und dann den Zendure Controller bauen.
Die neue Bridge (Proxy)
Zunächst einmal sei gesagt das Zendure anders als vielmals erwähnt oder behauptet, die Pakete nicht über Port 8883, also „MQTT over TLS“ verschickt, sondern unverschlüsselt über Port 1883 was noch ein Grund mehr für mich ist, die SolarFlow nicht ins Internet zu lassen. Dazu kommt, dass Zendure die Pakete mit QoS0 (Quality of Service Level 0) sendet, also „fire and forget“ was in dem Fall gut für mich ist. Denn so muss der Client ja gar nicht wirklich mit einem Brocker verbunden sein. Er muss nur denken das er es ist. Das Ganze nennt sich Mocking. Man erstellt einen TCP Socket auf Port 1883. Der MQTT Client verbindet sich dorthin, ist verbunden und ballert seine Pakete ins Nirvana.
So habe ich dann meine Bridge zum Testen umgebaut. Das weiterleiten von Port 1883 und 8883 habe ich entfernt. Dafür kam das oben erwähnte TCP Socket in den Code. Wer mal damit spielen will:
Python:
import socket
# TCP Server auf Port 1883 starten
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 1883))
server.listen(1)
print("Dummy-Broker wartet auf Clients...")
while True:
client_socket, addr = server.accept()
print(f"Verbindung von {addr}")
# 1. CONNECT Paket vom Client empfangen (wird hier ignoriert)
connect_packet = client_socket.recv(1024)
# 2. Das magische CONNACK zurücksenden
client_socket.send(b'\x20\x02\x00\x00')
print("CONNACK gesendet. Client ist drin!")
# 3. Jetzt kommen die QoS 0 Daten reingeflattert
while True:
data = client_socket.recv(1024)
if not data:
break
print(f"Rohdaten empfangen: {data}")
Da die DNS Anfragen an mqtt-eu.zen-iot.de eh schon an die 192.168.4.1 umgeleitet waren, verbindet sich der Hub nun mit dem digitalen Bermudadreieck. Nun Funktioniert technisch alles so wie ich es will. Ich kann die SolarFlow mit wenig Latenz ansprechen, sie ist nicht mit dem Internet verbunden und müllt mir nicht meinen MQTT Brocker voll.
Der Controller (Knoten im Hirn)
Das schlimmste wäre geschafft, dachte ich da noch. Welch wunderbarer Traum. Ich bekomme meine Stromzählerwerte über einen Hitchi Sensor der mir diese über Tasmota an den Broker schickt. Wenn ich nun eine Glühbirne einschalte, dauert es ca 3-6 Sekunden bis die Änderung am Stromzähler abzulesen ist. Für meine Stromkosten ist das nicht relevant aber es ist eine Latenz die bei der Regelung berücksichtigt werden muss. Dazu kommen konstante 3 Sekunden, bis die Änderung im Broker angekommen ist. Zum Zeitpunkt meiner Stellwertermittlung liegt das in der Vergangenheit. Nun setze ich den Stellwert und es dauert je nach Regelabweichung und Situation 1-16 Sekunden bis der Zielwert in der SolarFlow erreicht ist. Ist die SolarFlow in Regelung kann man von maximal 8 Sekunden ausgehen. Sowas steuert man nicht mehr über einem PID-Regler.
Also hab ich die KI befragt und als Antwort kam: Du brauchst einen Smith-Prädiktor. Das kam mir irgendwie bekannt vor, allerdings hatte ich vermutlich das letzte mal in der Ausbildung davon gehört. Aber warum einfach wenn’s auch kompliziert geht. Immerhin ist es in diesem Fall dann gleich ein Smith-Prädiktor mit zwei zeitlich variablen Messgrößen. Uiuiuiuiui, ich weiß gar nicht wie ich das beschreiben soll. In den Worten von Gemini:
Ein erweiterter Smith-Prädiktor für zwei zeitlich variable Messgrößen nutzt ein mathematisches Prozessmodell, um die jeweiligen, sich dynamisch verändernden Totzeiten beider Eingangsgrößen parallel zu simulieren und rechnerisch zu kompensieren. Dadurch kann der Regler auf Basis von verzögerungsfreien Vorhersagen agieren, noch bevor die echten, variablen Effekte an den Messstellen messbar sind. Auftretende Modellabweichungen werden über eine kontinuierliche Differenzbildung mit den realen Zählerwerten korrigiert, was den Regelkreis selbst bei schwankenden Latenzen stabil hält.
Gecheckt? Ok, dann kann’s weiter gehen. An diesem Punkt angekommen, wundert es mich nicht das der Akkudoktor (Andreas Schmitz) bei seinen DIY Regelungen immer nur 10 Watt hoch oder runter regelt. Das will ich so nicht haben. Man stelle sich vor: 600 Watt PV-Überschuss. Man lädt den Akku mit 600 Watt. Es kommt ne Wolke und es dauert in 10er Schritten multipliziert mit der Latenz erst mal 1½ Minuten bis der Sollwert auf 0 ist. Die Wolke ist weg und es dauert wieder 1½ Minuten bis die Regelung wieder bei 600 Watt ist.
Nun ist es in letzter Zeit sehr bequem geworden zu Programmieren. Man schreib die passenden Prompts zusammen, übergibt es dem LLM, prüft den erhaltenen Code und ändert die ein oder andere Stelle. So habe ich es auch diesmal gemacht. Das ging leider in die Hose. Nicht nur einmal. Die Regelung hat nicht das gemacht was sie sollte. Ich konnte dem LLM einfach nicht beibringen, das der Leistungswert des Stromzählers nicht der Absolutwert im Gesamtsystem ist. Hatte ich Gemini davon überzeugt die richtige Sollwertberechnung aus Beispielsweise Einspeiseleistung und Zählerwert zu berechnen, hat er es bei den Regelbedingungen wieder rausgeworfen. Mehrere Threads führten zu Todesspiralen. Die KI hat sich jedes mal aufs neue verrannt.
Also musste ich es wie früher selbst Programmieren was nunja doch recht langwierig ist, wenn man’s inzwischen anders kennt. Angefangen mit dem Interface! Danach eine „State Machine“ und am Schluss die Sollwertberechnungen je Zustand. Es war total Irre. Wann ist der Messwert so und wann so. Rein und raus, plus ist minus und eins ist NULL. Da weiß man nicht mehr ob man Männlein oder Weiblein ist. Aber das ist nicht das schlimmste. Man denkt es funktioniert alles, und dann kommt die Zendure Logik ins Spiel. Man könnte ja Meinen, wenn man einen Input Wert setzt, der die Leistung angibt mit der der Akku geladen wird, und einen Output Wert, der angibt wieviel Leistung eingespeist werden soll, das sich das gegenseitig verriegelt, zumal man mit dem Wert acMode:1 das Laden aktiviert und mit acMode:2 das Einspeisen. Dann müsste die Regelung funktionieren! Aber NEIN. Der Stromzähler springt wie ein Hoppelhase durch die Gegend und man fragt sich warum? Warum nur? Wo ist der Fehler? Doch man findet keinen Fehler! Und irgendwann schaut man in die App und sieht: Die Kiste lädt den Akku und speist gleichzeitig ins Haus ein, über das gleiche Kabel. Was ein Blödsinn. Dann findet man raus, das man erst Output:0 und Input:0 schicken muss, bevor man die Richtung umkehrt. Wenn man Output:0 und Input:300 hinschickt und gleichzeitig acMode:1 weil man mit 300 Watt laden will, überschreibt der Hub den Output nicht mit 0. Dabei funktioniert das perfekt in die andere Richtung. Und das ist auch noch Absicht. Ich muss mich verbessern. Denen fehlen keine Latten, die haben gar keine Latten mehr am Zaun.
Wie dem auch sei. Nach etlichen Korrekturen funktioniert der Controller inzwischen astrein. Besser sogar als ich erwartet habe. Er regelt fantastisch aus bis aufs letzte Watt. Und das innerhalb von Sekunden. Nach nun 3 Tagen hat er bis aufs BMS Kalibrieren alle Zustände durch, und die Tests bestanden.
Beim bauen der Firmware habe ich nun auch eine Funktion zum Updaten der Firmware „over the air“ eingebaut, auch mit Blick auf folgende Projekte. Nun kann ich beim Kompilieren unter folgenden Punkten wählen:
env:usb – Erstes beschicken oder für den Notfall über USB im Testbetrieb
env_test – Update OTA im Testbetrieb
env_live – Update OTA im Livebetrieb
In der Programmierumgebung muss ich einmalig einen „devicename“ angeben. Dieser wird als OTA-Hostname des ESP32 hinterlegt. Im Programmcode kann ich dann bei allen Funktionen sagen, was im Testbetrieb passieren soll, und was im Livebetrieb. So kann beispielsweise die Poolsteuerung laufen, während ich eine neue Version ohne die Sensoren teste. Sobald mir das Ergebnis passt schicke ich die neue Firmware als Live-Version auf den ESP32 im Pool wo er mit den Sensoren läuft, ohne das ich den Programmcode anpassen muss.
Achja, eine Ausgabe der wichtigen Zendure SolarFlow Werte landen inzwischen nahezu in Echtzeit auch auf meinem Brocker.
Mir fällt ein Riesen Stein vom Herzen, das dieses Kapitel endlich erfolgreich geschlossen werden kann. Nachdem alles läuft kann ich mir jetzt meine zweite Batterie zur Erweiterung bestellen.
Fazit
Lasst euch von Versprechen über „sich dem Markt öffnende Systeme“ nicht in die irre Führen. Auch wenn Hersteller mit Flexibilität und Zugänglichkeit werben, landen die Daten am Ende doch in der Cloud. Gekapselte Systemlandschaften wie die von Zendure sind für die Erweiterung bestehender Anlagen ungeeignet. Wer verhindern will, dass seine Anlagendaten im Internet landen, sollte einen Bogen um diese geschlossenen Ökosysteme machen.
Nachtrag 22.06.2026
Die Hardware von Zendure ist echt gut, da gibt es nichts zu Meckern. Meine zweiter Batterie kam, ich hab das System zusammengesteckt, und ab gings.
Den Softwareentwicklern hingegen hätte ich schon längst den Stöpsel gezogen. Vor ein paar Tagen sehe das mein SoC bei 100% ist, obwohl ich nach meiner Logik bei 90% aufhöre zu laden. Damit ich aber zum Kalibrieren des BMS einmal im Monat bis 100% laden will/muss, muss mein eingestellter Max-Limit Wert bei 100% sein. Jetzt ist mir gestern wieder aufgefallen das ich bei 94% noch lade. Meine App läuft im ERROR Modus, springt aus dem ERROR raus weil GET erfolgreich funktioniert, sendet POST mit {acMode: 1, InputPower:0, OutputPower:0} erfolgreich und springt beim Vergleichen der Soll und Istwerte wieder ins ERROR weil die Werte nicht zusammenpassen. Jetzt habe ich festgestellt, das Zendure kein acMode:1 also Laden mit 0 Watt kennt. In dem Fall denkt sich die Firmware, keinen Bock, ich schreibe einfach den Wert 0 nicht ins Register und lade einfach weiter.
Gestern wurde ein Projekt fertig, an dem ich schon länger gebastelt habe. Es war ein Projekt das mir sehr am Herzen liegt, wobei die Dringlichkeit immer mal wieder zu und abgenommen hat. Es handelt sich um eine Einkaufsliste die mehrere Personen nutzen können. „Ach, da gibt es ja hunderte im App-Store!“ könnte man mir sagen. Ja das stimmt, ist meine nüchterne Antwort, aber keine die so auf meine Wünsche und Bedürfnisse zugeschnitten ist.
Ich habe mir einige davon angeschaut, aber am Schluss bin ich dann mit meinem Schatz doch wieder in der WhatsApp Einkaufsgruppe gelandet.
Was sind denn nun meine Anforderungen?
Schnelles und einfaches hinzufügen von Produkten.
Wenig Traffic, kein Polling
trotzdem mehrere User auf einer Liste, also gemeinsames Einkaufen möglich
Aber jetzt kommt das wichtigste. Die Produkte sollen in der Reihenhole in der Liste stehen, wie sie auch im Supermarkt platziert sind. Und zwar für die Supermärkte in denen ich am liebsten einkaufe. Achja, und eine Rezeptdatenbank mit Produktverwaltung ist kurzfristig auch noch dazugekommen.
Aber schauen wir’s doch einfach an. Die Einkaufsliste läuft auf meiner Webpräsenz. Es wird unterschieden ob der Client ein Desktop- oder Mobil-Browser ist. Die Konfiguration ist am einfachsten über den Desktop zu erledigen. Produkte kann man entweder in der Produktverwaltung anlegen, über eine API, oder indem man sie einfach der Einkaufsliste hinzufügt. Hier entsteht zunächst ein Schattenartikel, dem man einen Namen und zusätzliche Informationen sowie ein Foto mitgeben kann. Nicht spezifizierte Produkte erscheinen immer am Ende der Einkaufsliste, sind aber für die Auswahl beim nächsten hinzufügen Auswählbar.
Bei vorhandenen Produkten bekommt man beim Tippen bereits Vorschläge gemacht und kann diese übernehmen.
Danach optional noch die gewünschte Anzahl und welche Maßeinheit.
Schon ist der Artikel in der Einkaufsliste. Gleiche Produkte mit gleicher Maßeinheit werden automatisch aufsummiert. Optionale Informationen und Fotos werden durch die Icons dargestellt und können angeklickt werde, wodurch sie in einem Overlay angezeigt werden. Ganz oben kann man seinen Wunschsupermarkt einstellen, wodurch sich die Sortierung der Produkte entsprechend anpasst. In der Produktverwaltung kann man Produkte direkt anlegen.
Beim Schreiben erhält man ebenfalls Hinweise, welches Produkt bereits vorhanden ist. Bei der Kategorie wird es nun interessant. Denn auf der Kategorie basiert die Navigation im Supermarkt. In der Produktverwaltung angelegten Produkten muss man gleich die Kategorie einstellen. Auch hier kann man Fotos knipsen, Bilder einfügen, und Notizen machen. Beliebte Produkte kann man als Favorit markieren. Hierfür gibt es auch eine Toggle Funktion in der Favoritenspalte. Fährt man mit der Maus drüber wird das Feld hervorgehoben und durch klicken kann man den Favoriten setzen oder entfernen. Anderweitig hinzugefügte Produkte haben die Kategorie „undefined“. Diese werden rot hervorgehoben und müssen von Zeit zu Zeit einer Kategorie zugewiesen werden. Die Kategorien müssen einmalig angelegt werden.
Hierzu habe ich in der Supermarkt-Scene recherchiert. Wie Supermärkte organisiert werden, welche Produkte wie platziert werden, und welche Produktgruppen daraus abgeleitet werden können. Diese habe ich angelegt und mit einem für mich passenden Emoji versehen.
Dann muss man diese Produktgruppen nur noch in der richtigen Reihenfolge für den Supermarkt per Drag & Drop hinschieben.
Supermarkt wählen! Grüne Kacheln sind sortiert, weiße nicht. Nun ist alles eingestellt.
Für mobile Geräte habe ich das als Web-App gebaut. Nachdem die App auf dem Bildschirm ist
kann sie geöffnet werden. Hier ist das Funktionsprinzip das gleiche, nur eben auf Touch optimiert. Nachdem alles eingestellt ist, kommt eine weitere interessante Funktion dazu. Beim klick auf das + öffnet sich ein weiteres Overlay. Hier kann man die Produkte direkt aus der Kategorie auswählen. Produkte die man häufiger benötigt findet man auch in den Favoriten wenn man diese gesetzt hat.
Zu guter Letzt gibt es noch den Barcodescanner den man in dieser Auswahl findet. Hier habe ich bereits erklärt worauf ich hinaus will. Ein weiterer Menüpunkt ist die Rezeptverwaltung.
Hier kann man Rezepte anlegen, und diesen Produkte zuweisen.
Hier gibt es das Produkt welches eine Zutat, eine optionale Zutat oder ein Gewürz sein kann. Mange, Einheit und Zusätzliche Informationen. Die Reihenfolge im Rezept kann man zudem noch einstellen. Hierfür habe ich die oben erwähnte API eingebaut. Man kann json in der richtigen Struktur direkt an die Schnittstelle schicken. Dann wird ein Rezept angelegt und die dazugerigen Produkte. Diese werden sofort geprüft, und wenn noch nicht vorhanden angelegt. So hat mein Rezept-Agent bisher 150 Rezepte mit den passenden Produkten in die Datenbank geschrieben. Zurück zum Scanner.
Barcode scannen. Wenn das Rezept richtig angelegt ist, findet er die Produkte.
Zutaten und Optionale Produkte werden zum Einkaufen vorselektiert, Gewürze nicht. Mit einem klick kann man korrigieren was man in der Einkaufsliste haben will. Über den Button Übernehmen werden die Markierten Produkte zur Einkaufsliste hinzugefügt. Das System lässt sich vielseitig einsetzen.
So, nun zum Einkaufen. Durch einen klick auf den Einkaufswagen hat man das Produkt in den Einkaufswagen gelegt. Hier gibt es wieder einen Toggle Mechanismus. Stellt man fest das man etwas falsches in den Einkaufswagen gelegt hat, kann man dieses durch erneutes klicken wieder Herausnehmen. Rausgehend werden nur die Daten des einen Produkts an den Webserver geschickt, eingehend bekommt man die gesamte Liste, um zu synchronisieren, wer sonst noch etwas eingekauft hat, oder gegebenenfalls etwas zusätzliches in die Einkaufsliste getan hat. Alles läuft über AJAX wodurch die Datenmenge stark reduziert ist. Es soll ja auch gehen wenn man mal schlechten Empfang hat.
Sind zu guter Letzt alle Produkte als Eingekauft markiert, werden diese in eine andere Tabelle verschoben, und die Einkaufsliste ist leer. Die historischen Einkäufe kann man sich dann auf einer weiteren Seite anschauen.
Ein Artikel über Meta, den ich im Internet gelesen habe, und die Aufgabe eines Trainees bei uns in der Firma hat mich dazu gebracht mir das Thema AI Agent’s anzuschauen. Vorweg möchte ich alle die das lesen dazu motivieren, sich aktiv mit dem Thema AI auseinanderzusetzen. Ich befürchte das alle, die jetzt nicht auf den Zug aufspringen, über kurz oder lang unter die Räder ebenjenes kommen. Die Tragweite meiner Aussage ist mir durchaus bewusst. Die aktuelle Entwicklung ist menschlich keine gute wie ich finde, aber die großen Player haben die Büchse der Pandora aufgemacht, und diese werden wir alle nicht mehr schließen können. Deshalb heißt es, mitschwimmen, den Kopf über Wasser halten, sonst säuft man ab. Das zeigt das Beispiel Meta. Hier ersetzen gerade KI Agent’s 8000 Mitarbeiter und Führungskräfte. Und das innerhalb von 4 Monaten Entwicklungszeit. Ob ich mit meinen Gedanken richtig liege wird die Zeit zeigen.
Solange schwimmen wir mal los … Die Funktionalität welche die großen Firmen gerade nutzen, kann man auch selbst als DIY Bastler hervorragend verwenden. Ich will das folgend an einem Beispiel zeigen und für Anregung sorgen. Ich weiß das ihr auf allerhand großartige Ideen und pfiffige Lösungen kommt, und freue mich schon darauf mich mit euch über eure Anwendungsfälle zu Unterhalten.
Für ein Projekt an dem ich gerade arbeite benötige ich Informationen die auf kleine Karten gedruckt sind. Diese sollen ausgelesen und als JSON zur Verfügung gestellt werden. Dazu habe ich einen Agent gebaut, was recht simpel war. Zunächst einmal die Ordnerstruktur und die Dateien anlegen.
In der Datei agent.py ist das Python Script für den Agent. In .env ist der API-Key gespeichert. Diesen kann man sich unter aistudio.google.com holen.
Sobald man einen API-Key hat, kann man prüfen welche Modelle einem zur Verfügung stehen
Python:
# Test-Script zum Auflisten der Modelle
for model in client.models.list():
print(f"Name: {model.name}, Supported Methods: {model.supported_actions}")
Für Gemini 1.5 Flash beispielsweise sind die kostenlosen Limits folgendermaßen: Rate Limit: Bis zu 15 Anfragen pro Minute (RPM). Tageslimit: Bis zu 1.500 Anfragen pro Tag (RPD). Token-Limit: 1 Million Token Kontextfenster.
Jetzt schreibt man einen Prompt für die Aufgabe die der Agent ausführen soll:
Prompt:
Du bist ein spezialisierter Assistent zur Datenextraktion aus Bilddateien. Deine Aufgabe ist es, Informationen von einer Rezeptkarte in ein präzises JSON-Format zu überführen.
Analyse der Bildbereiche:
Rezeptname: Befindet sich oben links in der weißen Box.
Rezeptgruppe: Befindet sich oben rechts in der weißen Box.
QR-Code: Befindet sich unten in der Mitte.
Zutaten: Liste auf der rechten Seite unter der Überschrift "Zutaten".
Optionale Zutaten: Falls vorhanden, unter der Überschrift "Optional".
Gewürze: Falls vorhanden, unter der entsprechenden Überschrift.
JSON-Strukturvorgaben:
Verwende exakt die folgende Struktur. Wenn eine Kategorie fehlt, setze null oder [].
Achte darauf, Menge und Einheit korrekt zu trennen. Falls keine Einheit angegeben ist, verwende null.
Wichtig: Gib als Antwort ausschließlich den reinen JSON-Code zurück. Keine Erklärungen, kein Markdown-Code-Block.
{
"rezeptname": "String oder null",
"rezeptgruppe": "String oder null",
"qr_code": "String oder null",
"zutaten": [],
"optional": [],
"gewuerze": []
}
Zuguterletzt fehlt noch das Python Script, wofür zusätzliche Pakete benötigt werden.
Das Script schaut im Ordner img_new ob es dort Bilder gibt. Die Bilder werden geladen und an das Model übergeben. Das Ergebnis wird als JSON File gespeichert und das Bild entweder als erledigt in den vorgesehenen Ordner geschoben oder in den Error Ordner.
Das Sahnehäubchen bildet inotify welches in jedem Linux Kernel integriert ist. Um es zu nutzen verwenden wir inotify-tools
Vor ein paar Tagen habe ich mir für meinen Energieüberschuss auf Empfehlung von bis dahin zwei Kollegen eine Zendure 1600 AC+ gekauft. Eigentlich wollte ich mir meinen Speicher selbst bauen, aber man muss ja nicht für alles das Rad neu erfinden. Nun ist es leider so, das man die Kiste nur mit dem in der Firmware hinterlegten MQTT Broker verbinden kann. Meine Meinung zu Home-Automation ist strikt. Das Wort steckt schon im Begriff, nämlich „Home“. In diesem Zusammenhang kann ich mit dem ganzen IoT und Cloud Wahn überhaupt nichts anfangen. Es ist ja schließlich auch noch niemand auf die Idee gekommen, das eigene Stromkabel zu Hubel-Heiner-Butzenbach den ich mal Bernd nenne und der zwei Straßen weiter wohnt zu legen, dort in einen Schaltkasten, und von dort wieder zurück. Um den eigenen Treppenhausautomaten dort unterzubringen, damit Bernd immer schauen kann wann ich in den Keller gehe und das zu protokollieren. Der Clou an Bernd und anderen Anbietern wie Shelly, Bosch, Zendure uvm. ist, das man sich seine live Daten anschauen kann (Ahhh das Licht ist an!) die Historischen Daten aber in Bernds Tresor landen, und mir diese nicht frei zur Verfügung stehen. Wie wenn das Bernds und nicht meine Kellergänge gewesen wären. Und wenn der Bernd glaubt, nicht genug dran zu verdienen, oder keine Lust mehr hat, schaltet er einfach meinen Treppenhausautomaten ab. Bernd argumentiert dann: Trotz aller Bemühungen und des innovativen Konzepts wurde nicht die für einen wirtschaftlichen Weiterbetrieb erforderliche Marktakzeptanz erreicht!
Wo war ich stehen geblieben? Ah ja, wer sagt denn, das ich meinem Server in meinem lokalen Netzwerk nicht den alias mqtt-eu.zen-iot.de geben kann und somit die Zendure 1600 AC+ mit meinem MQTT spricht?! Das eine nennt man Spoofing und das andere Hijacking was garnichtmal so trivial ist.
Da ich das nicht über meinen Linux Server lösen, dort Sicherheitslöcher aufreißen und etliche vorhandene, funktionierende Sachen verbiegen wollte, habe ich mich für einen anderen Weg entschieden. In meiner Bastelbox liegen seit ein paar Tagen zwei brandneue ESP32 S3 DevKit1 R16N8. Mit 16MB Flash und 8MB PSRAM haben die um einiges mehr Ressourcen als meine bisherigen. Sollte also für eine TCP-Bridge reichen.
Also erst mal schauen was alles von Zendure erwartet wird. HTTP Token (TCP), MQTT (TCP), NTP (UDP) oha. Ohne Uhrzeit lässt sich die 1600 AC+ nicht regeln.
Erst mal mit dem Programmieren anfangen. Zunächst einmal einen Accesspoint mit WPA aufspannen. Zum Testen auf 192.168.4.1 (default) und über das Webinterface auf Port 8080 konfigurierbar machen. Dann nach SSIDs scannen und das Zielnetzwerk einstellbar machen. Zudem die Target IP also mein persönlicher Server einstellbar machen. Zum Testen wird die 192.168.1.10 verwendet. Zur Sicherheit habe ich eine Whitelist eingebaut. Nur erlaubte Domains dürfen auf meinen Server. Um das zu prüfen musste noch ein Log ins Interface. Dann noch DNS und TCP einbauen.
Was passiert nun? Der Client meldet sich am ESP32 Accesspoint an, bekommt den Gateway und den DNS 192.168.4.1 sowie eine freie IP in diesem Netzwerksegment. Wenn der Client nun beim DNS nach der IP von Beispielsweise google.com fragt, bekommt er die 192.168.4.1 zurück insofern die Domain in der Whitelist ist. Intern werden die Pakete über die TCP-Bridge welche die WIFI Klasse mitbringt an die Target-IP weitergeleitet, und von da die Antwort zurück.
Funktioniert astrein.
Bei NTP schaut die Sache nun anders aus. Das User Datagram Protocol (UDP) hat zwar einen Header, aber dieser beinhaltet keine Quell und Zieladressen. Die werden eine Schicht darüber im IP-Header geführt. Das ist in meinem Fall ein Problem. Der Client schickt die Anfrage zur .4.1 wo es ausgepackt wird. Hier sieht mein Proxy das es eine NTP Anfrage auf Port 123 ist. Dieses kann ich nehmen, und auf der anderen Seite wieder als UDP an meinen Server, den Router oder einen anderen NTP-Server schicken welcher mit der Uhrzeit antwortet. Da aber der ESP32 vergessen hat von wem die Anfrage gekommen ist, endet der Rückweg hier. Es muss ein simuliertes abgespecktes Network Address Translation (NAT) her. Also habe ich eine Funktion für NAT-light eingebaut. Das hat soweit geklappt, benötigt aber viele Ressourcen und bremst den Proxy aus. Zudem ist das System unzuverlässig sobald zwei Clients UDP anfragen stellen, da der eine den anderen im schlechten Fall überschreibet. Also habe ich rumgekämpft, die NAT-Funktion weiter aufgeblasen um das System noch langsamer zu machen. Hat mir alles nicht gefallen. Beim drüber schlafen habe ich mir die Sache nochmal durch den Kopf gehen lassen. Wenn doch der Client eh nur die .4.1 sieht, dann kann er doch von da auch die Urzeit bekommen. Und so läufts. Der ESP32 holt sich beim Boot und in regelmäßigen Abständen die Uhrzeit bei de.pool.ntp.org und stellt sie selbst als NTP zur Verfügung.
Bernd, wenn du dich persönlich angegriffen fühlst, möchte ich mich dafür entschuldigen. Der Name ist Rainer Zufall! Äh nein Rainer, nicht ganz. Welches international agierende Unternehmen mit dem Hang zur Verlagerung beginnt nochmal mit dem gleichen Buchstaben?
Warum nicht direkt NAT verwenden. Weil die Klasse gekapselt ist, und Eingriffe wie ich sie benötige nicht hergibt ohne diese umzuschreiben.
NTP beinhaltet nicht nur die Uhrzeit. Uhrzeit war aber einfacher zu schreiben.
Es ist zu erwähnen das google.com für meine ersten Tests die schlechtmöglichste Wahl war. Aber man lernt nie aus. Moderne Browser sind sogenannte HSTS Browser. Beim Aufruf einer Website kann diese dem Browser mitteilen, das zukünftig oder für eine gewisse Zeit der Verbindungsaufruf auf eine andere Adresse umgeändert wird. Es ist gar nicht so einfach dem Browser zu sagen das er bei google.com nicht https://www.google.com/?hl=de aufrufen soll.
Eigentlich ist dies ein Beitrag, den ich nie schreiben wollte.
Ich hatte eine einfache Grundregel: Auf diesem Blog erkläre ich keine Systeme oder Werkzeuge, die — unabhängig von ihrer technischen Legitimität — auch gezielt von Kriminellen eingesetzt werden, um Straftaten zu verschleiern. Nicht, weil ich diese Werkzeuge ablehne, sondern weil mir bewusst ist, dass Wissen Verantwortung bedeutet.
Und dennoch schreibe ich heute über die Einrichtung von Mullvad VPN.
Der Grund dafür ist kein technischer, sondern ein politischer.
Was für mich das Fass zum überlaufen gebracht hat, war vor ein paar Tagen die Aussage von Bundeskanzler Friedrich Merz auf einer Konferenz in Trier, in der er das Internet ausdrücklich als politischen Debattenraum bezeichnete und daraus die Notwendigkeit einer Klarnamenspflicht ableitete. Spätestens an diesem Punkt wurde mir klar, dass sich ein grundlegendes Missverständnis festgesetzt hat: Das Internet wird von Teilen der Politik offenbar nicht als Infrastruktur verstanden, sondern als eine Art öffentlicher Marktplatz.
Doch das World Wide Web ist kein Marktplatz.
Es ist der größte, offenste und zugleich gefährlichste Kommunikationsraum, den es gibt. Dort bewegen sich Staaten, Unternehmen, Nachrichtendienste, Betrüger, Datensammler und organisierte Kriminalität zugleich. Wer sich verbindet, exponiert sich technisch. Diese Realität verschwindet nicht dadurch, dass man sie politisch anders bezeichnet.
Deshalb bin ich der Meinung nicht die Nutzung von Schutzmaßnahmen ist erklärungsbedürftig, sondern ihre Nichtnutzung.
Die Entwicklung der letzten Jahre
(EU) 2016/679 – Ein Teil dieser Entwicklung begann mit der Datenschutz-Grundverordnung. Die DSGVO hatte ein legitimes Ziel: Bürgern bewusst zu machen, dass ihre personenbezogenen Daten nicht herrenlos sind und dass sie ein einklagbares Recht darauf haben, dass Daten gelöscht werden können. Dieser Gedanke ist richtig. Gleichzeitig waren die wirtschaftlichen Folgen erheblich. Zurückhaltende Schätzungen gehen davon aus, dass allein die Umstellung die deutsche Wirtschaft 50 Milliarden Euro gekostet hat, ohne die laufenden Kosten zu betrachten. Kosten, die letztlich über die Preise beim Bürger landen. Man muss festhalten: Die DSGVO hat nicht das grundlegende Problem gelöst, nämlich den technischen Selbstschutz des Einzelnen im Netz.
§ 188 StGB – Parallel dazu wurde § 188 erweitert, der besondere Ehrschutz für Personen des politischen Lebens. Kritiker sehen darin eine Ungleichbehandlung im strafrechtlichen Schutz persönlicher Ehre. In der Praxis hat sich zudem ein neues Phänomen entwickelt: automatisierte Auswertung öffentlicher Äußerungen im Internet und daraus resultierende juristische Verfahren. Unabhängig von der Bewertung zeigt das vor allem eines — Äußerungen im Internet sind längst kein flüchtiges Gespräch mehr, sondern dauerhaft verwertbare Information.
§ 113 TKG – Schon heute müssen alle Telekommunikationsanbieter Verbindungs- und Metadaten für 14 Tage speichern. Über Jahre wurde politisch über die anlasslose Speicherung gestritten – offiziell aus Gründen der Strafverfolgung und Gefahrenabwehr, faktisch aber ein Generalverdacht gegenüber allen Nutzern. Geplant ist nun eine Ausweitung auf drei Monate, was nicht nur zusätzliche Kosten für die Verbraucher bedeutet, sondern den praktischen Nutzen infrage stellt: Überlastete Gerichte können die Daten kaum zeitnah auswerten. Gleichzeitig steigt das Risiko, dass sich auch hier eine Klageindustrie entwickelt, die automatisiert auf kleinste Verstöße reagiert, da die geplanten Änderungen neue Angriffspunkte schaffen.
Aus den beschriebenen Entwicklungen ergibt sich ein grundlegender Widerspruch: Während Bürger zunehmend verpflichtet werden, identifizierbarer zu werden, wächst gleichzeitig die Bedrohungslage im Netz gerade in Zeiten von KI enorm. Daten und Identitätsdiebstahl, Social-Engineering-Angriffe und automatisierte Betrugssysteme sind Alltag.
Verhältnismäßigkeit und Realität
Wenn ich das Internet mit einem physischen Ort vergleichen müsste, dann wäre es kein offener Marktplatz — sondern eher eine dunkle, unübersichtliche Gasse sichtbarer und unsichtbarer Akteure. In einer solchen Umgebung dürfte niemand ernsthaft fordern, das ein Kind ein Schild tragen muss auf dem steht: „Ich bin Susi, 12 Jahre alt“
In der analogen Welt existierten schon vor dem Internet Schutzprinzipien:
• das Briefgeheimnis (Art.10 GG), • die Vertraulichkeit der Telekommunikation (TKG §88-91), • das Recht sich frei zu versammeln (Art.8 GG), • das Recht auf Anonymität abgeleitet aus (Art.2 Abs.1 Grundgesetz)
Niemand verlangt, dass auf jedem Brief außen der vollständige Lebenslauf steht. Niemand würde akzeptieren, dass jede Postverbindung pauschal protokolliert wird. Und doch bewegen wir uns im Internet zunehmend in genau diese Richtung.
Die eigentliche Fehleinschätzung ist daher nicht technischer, sondern struktureller Natur: Das Internet ist keine Debattenplattform — es ist Infrastruktur. Und Infrastruktur benötigt Sicherheit.
Warum dieser Artikel existiert
Ich breche mit meiner eigenen Regel, weil sich die Rolle verschoben hat.
Früher bedeutete die Erklärung von Anonymisierungs- oder Schutztechniken jemandem beim Verbergen zu helfen. Heute bedeutet das Weglassen dieser Informationen zunehmend, Menschen ungeschützt zu lassen. Zwischen Verschleierung und Selbstschutz besteht ein entscheidender Unterschied.
Meine persönliche Schlussfolgerung ist daher einfach:
Sobald ich eine Verbindung mit dem World Wide Web herstelle, öffne ich eine Tür zu einem potenziell gefährlichen Raum. Das muss jedem bewusst sein — auch politischen Entscheidungsträgern. In diesem Raum geht es um Sicherheit und vor allem um Eigenschutz. Und wenn staatliche Maßnahmen diesen Schutz nicht gewährleisten oder ihn sogar verringern, dann bleibt nur eine Konsequenz:
Ich muss mich und meine Familie selbst schützen.
Vorbereitung
Im folgenden erkläre ich unabhängig meines eigenen VPN-Gateways die Einrichtung von Mullvad VPN auf einem Raspberry PI mit nur einem Netzwerkadapter.
Voraussetzungen: • Router 192.168.100.1 • Raspberry PI 192.168.250.250, 192.168.100.250 • Raspberry PI OS (Debian) vorinstalliert • A klitzeklois bissle Ahnong vo Linux du Dackel
Zunächst muss die Möglichkeit geschaffen werden, dem Client den Raspberry PI als Gateway vorzugeben. Eine Möglichkeit ist es, IP Adresse, Gateway sowie DNS am Client fest einzustellen. Ich möchte eine flexiblere Lösung aufzeigen. Der D-Link DAP2695 beispielsweise bietet dafür eine Ausgezeichnete Möglichkeit. Zunächst legt man eine Zusätzliche SSID an, in meinem Fall sycotec-secvpn. Danach ein virtuelles logisches Teilnetzwerk, hier VLAN10. Diesem weist man über SSID-to-VLAN Mapping die neue SSID zu. Danach muss noch der DHCP konfiguriert werden.
SSIDVLANDHCP
Bei dieser Konfiguration ist es nun so, das der WLAN-Client bei der default SSID die Netzwerksettings vom DHCP des Routers bekommt. Verbindet man sich über die SSID sycotec-secvpn erhält man die Netzwerksettings vom DHCP des Accesspoints, landet im Segment 192.168.250.0 und bekommt den Raspberry Pi als Gateway.
Einrichtung des VPN Gateways
Idealerweise macht man zunächst ein Update der Paketliste und des Betriebssystems
sudo apt update
sudo apt upgrade -y
um danach die neusten Pakete von wireguard, nftables, dnsmasq und curl zu installieren, falls noch nicht vorhanden.
Folgend muss der Pi in die beiden Netze IN (192.168.250.250) und OUT (192.168.100.250). Dazu wird /etc/network/interfaces wie folgt geändert:
auto eth0
iface eth0 inet static
address 192.168.100.250
netmask 255.255.255.0
gateway 192.168.100.1 # IP des Routers
dns-nameservers 192.168.100.1
# Virtuelles Interface für secvpn Subnetz
auto eth0:1
iface eth0:1 inet static
address 192.168.250.250
netmask 255.255.255.0
Der DNS Server spielt an dieser Stelle für den VPN keine Rolle. Damit Linux Routen kann, muss IP Forwarding unter /etc/sysctl.conf aktiviert werden.
net.ipv4.ip_forward=1
Danach meldet man sich mit seinen Zugangsdaten unter https://mullvad.net/ an, und wählt dort „WireGuard configuration“. Ich habe mich für einen Ausgang in Island entschieden da diese eine Hervorragende Infrastruktur haben, und dort die Privatsphäre sehr hoch aufgehängt ist. Dafür wählt man
• Server location: Iceland • Device: Linux • Tunnel: WireGuard
aus und startet den Download. Den Inhalt der mullvad.conf kopiert man nun in die Datei /etc/wireguard/wg0.conf welche dann folgende Struktur hat:
Wichtig ist hier das AllowedIPs auf 0.0.0.0/0 steht, damit sämtliche Packete durch den Tunnel gezwungen werden. Nun können wir WireGuard probehalber schonmal starten und schauen ob der Tunnel funktioniert.
sudo wg-quick up wg0
curl https://am.i.mullvad.net/ip
Hier sollte nun Country: Iceland stehen. Wenn der VPN nicht läuft bekommt man lediglich die aktuelle Internet IP angezeigt. Wenn’s nicht geht, gehe zurück zum Start, gehe nicht über Los und ziehe nicht 200 Mark ein. Alles Punkt für Punkt überprüfen und schauen ob alle Dienste laufen. Ansonsten … weiter geht’s. Da wir nicht wollen, das uns der DNS verrät zwingen wir diesen auch durch den Tunnel und nehmen den DNS von Mullvad. Dazu editieren wir die Datei /etc/dnsmasq.conf
Wichtig bei der Nutzung eines VPN Gateways als „Router“ ist es sich vorher genau zu überlegen welche Endgeräte man durch den Tunnel schicken will und welche nicht. Darauf aufbauend muss man sich das Konzept überlegen. Hier gibt es für fast alles eine Lösung. Aber Achtung, Streaming Anbieter sind bei „Geo Blocking“ sehr empfindlich und auch die VPN Tunnel von Arbeitgebern mögen es zuweilen überhaupt nicht ihrerseits getunnelt zu werden. Ganz paranoide haben noch die Möglichkeit ihre DNS Abfragen mit dnscrypt-proxy über DoH (DNS over HTTPS) laufen zu lassen. Über diesen Vorschlag gab es bei ein paar Bierchen einen angeregten Austausch. Danke dafür.
Noch ein paar wichtige Tips: Wenn an den config-files von laufenden Diensten etwas geändert wird, müssen die Dienste zumeist neu gestartet werden. Die Regeln von iptables-persistent und netfilter-persistent müssen gespeichert werden um sie nach einem reboot noch zur Verfügung zu haben.
Nachdem bei mir viel Interesse am Thema AI bekundet wurde, habe ich die Fragen gesammelt. Dabei wurde mir klar, das die meisten noch keine Berührungspunkte mit LLM’s (Chatbots) also der Basis der häufigsten KI Anwendungen hatten.
Aus diesem Grund habe ich meinen Post Howto AI als Grundlage genommen und ein Tutorial für die Nutzung von ChatGPT erstellt. Da sich bis zur Fertigstellung des Tutorials nicht mehr viel zu diesem Thema in meinem Posteingang getan hat, lag das Teil nun eine ganze Weile ganz weit unten in meiner Schublade.
Kürzlich hatte ich dann eine interessante Unterhaltung mit einem Kollegen zu diesem Thema. Während dieser Unterhaltung kam raus, das die „Hemmschwelle“ sich bei OpenAI anzumelden das größte Hindernis für „Neulinge“ darstellt.
Also habe ich das Tutorial nochmal überarbeitet und Gemini als LLM verwendet, da man diesen direkt über die Google Startseite aufrufen kann.