Wir machen einen Controller für ein Smart Home und nicht nur.
In einem früheren Artikel habe ich die Entwicklung des gesamten Systems beschrieben. In diesem Artikel werde ich die Entwicklung eines Controllers beschreiben, der für die Abfrage von Sensoren und E / A-Modulen verantwortlich ist. "Warum das Rad neu erfinden?" - Du fragst. Erstens ist es interessant, und zweitens gibt es seltsamerweise keine OpenSource-Lösung für einen solchen Controller, der sowohl Software als auch Hardware abdeckt. Der Artikel richtet sich an Personen, die sich mit Elektronik und Embedded Linux-Entwicklung auskennen.
Die Herstellung eines Controllers ist so kompliziert - Sie müssen eine Karte erstellen, Software schreiben und den Fall drucken. Aber in Wirklichkeit ist alles etwas komplizierter, das hat es mir gebracht, aber Sie haben im Prinzip Recht:
1. Controller-Hardware
- Wahl der CPU-Karte für den Controller
- Wahl des IO-Controllers
- Wahl der Stromversorgung
- Blockschaltbild der Steuerung
- Entwicklung eines Crossboards für die Steuerung
- Entwicklung von Karten für RS-485-Module
- Herstellung von Brettern
2. Software für die Steuerung
- Wahl des Build-Systems für Linux-Kernel und Rootfs
- Partitionsstruktur der SD-Karte
- Auswahl des Bootloaders und Laden der erforderlichen Rootfs
- Änderungen im Gerätebaum
- die Wahl eines Systems zum Einzug von gehandelten Belastungen
- Schreiben eines Build-Systems
- Schreiben eines Kommunikationskerns
- Schreiben eines mqtt-Gateways (diskrete / analoge Controller-Punkte -> mqtt-Themen)
- Schreiben eines Google-Parsers und Erstellen einer JSON-Konfigurationsdatei für das Gateway
- Schreiben eines Punktmonitors für den Zugriff auf Controller-Punkte
- schreibgeschütztes Dateisystem einbinden
3. Controller-Gehäuse
- Was sollte sein, Anschlüsse, Kühlung, Sitze für eine Platine, Hypotheken für Clips für Klammern an einer Dinrake.
- Design und Druck
Ein paar Worte zur Hardware.
Wahrscheinlich nehmen nur die Verzweifeltesten jetzt einen separaten Prozessor, Speicher, Flash, Leistungsregler, ein paar weitere hundert Komponenten und beginnen, alles zusammen zu formen. Der Rest nutzt die Früchte der Arbeit anderer Leute, es ist schneller und einfacher. Sie müssen nur einen Browser öffnen und "Single Board Computer" schreiben und den Rest des Tages damit verbringen, den richtigen auszuwählen. Ich brauchte viele serielle Schnittstellen und es ist wünschenswert, dass die Platine -40 ° C bis + 85 ° C unterstützt, daher fiel die Wahl auf BeagleBone Black (BBB). Auch bei BBB sind alle Peripheriegeräte in Schritten von 2,54 mit zwei PBD-Anschlüssen mit 46 Pins verbunden, was für das Prototyping und die Entwicklung einer Cross-Board praktisch ist. Eine Kreuzplatine wird benötigt, um alle Komponenten auf einer Platine zu kombinieren. Für mich handelt es sich um eine CPU-Platine, ein Netzteil, einen E / A-Controller und RS485-Kanalplatinen. Außerdem muss die Kreuzplatine am Gehäuse befestigt werden, und es befinden sich Anschlüsse für die Stromversorgung und das RS485-Kabel.

Also haben wir die CPU-Karte herausgefunden. Als nächstes müssen wir entscheiden, ob ein E / A-Controller (Input / Output) auf der Cross-Board installiert werden muss oder nicht. Ich habe es auf die Tafel gelegt und es noch nicht erfolgreich benutzt. Das einzige, was er tut, ist, den Start der BBB nach dem Einschalten um 1s zu verschieben und die Reset-Taste zu drücken.
Das Netzteil für den Controller habe ich mit dem vorgefertigten MeanWell NSD10-12S5 genommen. Die Entwicklung für ein einzelnes Gerät ist ein bedeutungsloses Unterfangen. Ich habe es nur für den Verbrauch abgeholt und das wars. Achten Sie nicht auf das LCD, es befindet sich auf der Platine, aber ich habe keine Unterstützung implementiert.


Ein paar Worte zu RS485-Kanalkarten.
Auf der Kreuzplatine befinden sich 4 serielle BBB-Schnittstellen. Dort können Sie jede Art von Kanal platzieren, RS485, CAN, ZigBee-Modul ...
Ich brauchte RS485-Kanäle, also habe ich nur diese gemacht, sie sind mit automatischer Empfangs- / Sendesteuerung und mit galvanischer Trennung. Warum nicht die Transceiver-Steuerung mit BBB verwenden, da TI den Strobe für RS485 im seriellen Gerätetreiber offiziell nicht mehr unterstützt? Sie können einen Patch für den Treiber finden, Sie können ihn selbst hinzufügen, aber warum? Nachdem Sie den Kanal selbstsperrend gemacht haben, können Sie ihn auf ein beliebiges Board setzen, z. B. auf RaspberyPi, wo es noch nie eine solche Unterstützung gegeben hat. Wenn ja, korrigieren Sie mich. Der Blitz für den rs485-Treiber ist auf attiny10 konfiguriert, billig und fröhlich.
Wir kehren zur Software zurück.
Auswählen eines Build-Systems für den Linux-Kernel und rootfs.
Es gibt verschiedene Systeme dieser Art, die beliebtesten sind Yocto und BuildRoot. Wenn Sie ein großes Projekt entwickeln müssen, viel Zeit haben und Rezepte schreiben möchten, ist Yocto Ihre Wahl. Mit Hilfe von BuildRoot können Sie alles sammeln, was Sie zum einfachen Starten des Boards benötigen. Das ist sehr, sehr einfach, weil Ich mache ein System auf Beaglebone Black (im Folgenden BBB) dann:
- Lesen Sie, was hier geschrieben steht habr.com/en/post/448638
- sauber machen
- mache beaglebone_defconfig
- machen
Das ist alles. Jetzt befindet sich alles, was Sie zum Ausführen des Boards benötigen, im Ordner / buildroot / output / images.
Alles sieht sehr einfach und nicht interessant aus, so dass Sie etwas komplizierter machen können:
- Integrieren Sie buildroot in Ihr Build-System, laden Sie es mit einem Skript herunter, denken Sie daran, ein stabiles Tag zu verwenden, und nehmen Sie nicht die letzte Entwicklung vor
- Schreiben Sie Ihre defconfig und werfen Sie das Skript in den Ordner / buildroot / configs, bevor Sie buildroot zusammenstellen. Vergessen Sie nicht, dass alle defconfigs mit * _defconfig enden müssen, sonst sieht buildroot es nicht
- Kopieren Sie Ihre post-build.sh nach board / beaglebone / post-build.sh
- Bereiten Sie ein Skript vor, das n1, n2 und n3 für Sie erledigt
Infolgedessen generiert buildroot zImage und rootfs.tar
Auswahl der Partitionsstruktur der SD-Karte:
Ich denke, es ist nicht notwendig, viel Aufmerksamkeit darauf zu richten.
Ich habe 4 Abschnitte BOOT / ROOT_1 / ROOT_2 / DATA gemacht.
Der BOOT-Abschnitt enthält alles, was Sie zum Bootstrapping benötigen: MLO, barebox.bin, barebox.env, am335x -boneblack.dtb, zImage, boot.txt.
ROOT_1 und ROOT_2 enthalten rootfs, deren Auswahl in die Datei boot.txt geschrieben ist (siehe unten). Alle diese Partitionen werden schreibgeschützt gemountet, um Abstürze des Dateisystems beim Ausschalten zu vermeiden. DATA enthält Designkonfigurationen, bei deren Änderung der Code nicht neu erstellt werden muss.
Eine solche Struktur von Partitionen wird es in Zukunft einfacher machen, eine Software-Update-Komponente zu schreiben. Diese Komponente überschreibt einen der Abschnitte ROOT_1 / ROOT_2, der derzeit nicht verwendet wird, und ändert dann einfach die Datei boot.txt, wenn Sie den Kernel nicht ändern müssen.
Bootloader auswählen.
Ich hatte viele Experimente mit Bootloadern für BBB. Zuerst habe ich wie alle anderen den U-Boot verwendet, den BuildRoot generiert. Aber es hat mir nicht gefallen, vielleicht ist das natürlich eine Gewohnheit, aber es schien mir, dass es zu viel war, es ist sehr schwer und schwer zu konfigurieren. Dann dachte ich, dass es keine schlechte Idee wäre, das System schnell in 2-3 Sekunden zu starten und den X-Loader abzulegen, damit er den Kernel lädt. Es gelang mir, aber es gab wieder ein Konfigurationsproblem und die Startzeit für mich nicht kritisch (das System auf systemd startet langsam von selbst, selbst wenn Sie alles löschen, was nicht benötigt wird).
Am Ende habe ich mich für Barebox entschieden, die Einfachheit hat mir sehr gut gefallen und die Website enthält die gesamte Dokumentation (www.barebox.org).
Um beispielsweise rootfs von der ersten oder zweiten Partition zu laden, müssen Sie nur:
1. Erstellen Sie im Boot-Bereich die Datei boot.txt, die eine Variable vom Typ "export BOOT_NUM = X" exportiert.
2. Erstellen Sie zwei Skripte / env / boot / sdb1 / env / boot / sdb2, in denen die Startoptionen beschrieben werden, zum Beispiel:
echo "botting with mmcblk0p2 as rootfs..." global.bootm.image=/boot/zImage global.bootm.oftree=/boot/am335x-boneblack.dtb global.linux.bootargs.console="console=ttyO0,115200" global.linux.bootargs.debug="earlyprintk ignore_loglevel" global.linux.bootargs.base="root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait"
3. Erstellen Sie ein Skript / env / boot / sd, in dem Sie je nach BOOT_NUM das Skript sdb1 oder sdb2 starten
4. Setzen Sie die Variable boot.default
nv boot.default=sd saveenv
5. Wenn Sie BOOT_NUM in boot.txt weiter ändern, werden wir rootfs von der ersten oder zweiten Partition laden, die in Zukunft für Software-Updates verwendet werden können.
Änderungen am Gerätebaum.
Da ich MODBUS RTU über RS485 für die Kommunikation mit den Modulen verwende, musste ich fast alle seriellen Schnittstellen aktivieren, die auf der BBB vorhanden sind. Dazu müssen Sie sie im Gerätebaum wieder aktivieren, weil Standardmäßig sind die meisten von ihnen deaktiviert.
Es wäre richtig, Ihren Patch für die Datei am335x -bone-common.dtsi aus dem Buildrut-Paket zu erstellen und jedes Mal vor dem Zusammenstellen anzuwenden, aber die Faulheit hat gewonnen und ich habe einfach alle benötigten Dateien herausgezogen, alles, was ich brauchte, geändert und mit meinen Händen aufgebaut.
Weil Dies wird einmal gemacht, es ist möglich und so:
1. Erstellen Sie einen Ordner mit den für die Montage erforderlichen Dateien:
am335x-bone-common.dtsi am335x-boneblack-common.dtsi am335x-boneblack.dts am33xx-clocks.dtsi am33xx.dtsi am33xx.h gpio.h omap.h tps65217.dtsi
2. In der Datei am335x -bone-common.dtsi müssen Sie die Pins korrekt konfigurieren und die Port-Treiber deaktivieren:
uart1_pins: pinmux_uart1_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0) AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0) >; }; uart2_pins: pinmux_uart2_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE1) AM33XX_IOPAD(0x954, PIN_OUTPUT_PULLDOWN | MUX_MODE1) >; }; uart4_pins: pinmux_uart4_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE6) AM33XX_IOPAD(0x874, PIN_OUTPUT_PULLDOWN | MUX_MODE6) >; }; uart5_pins: pinmux_uart5_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x8C4, PIN_INPUT_PULLUP | MUX_MODE4) AM33XX_IOPAD(0x8C0, PIN_OUTPUT_PULLDOWN | MUX_MODE4) >; }; &uart1 { pinctrl-names = "default"; pinctrl-0 = <&uart1_pins>; status = "okay"; }; &uart2 { pinctrl-names = "default"; pinctrl-0 = <&uart2_pins>; status = "okay"; }; &uart4 { pinctrl-names = "default"; pinctrl-0 = <&uart4_pins>; status = "okay"; }; &uart5 { pinctrl-names = "default"; pinctrl-0 = <&uart5_pins>; status = "okay"; };
3. Als nächstes ein wenig Magie, und die fertige Datei am335x -boneblack.dtb befindet sich im selben Verzeichnis:
a. sudo apt-get install device-tree-compiler
b. Führen Sie den Präprozessor aus:
cpp -Wp,-MD,am335x-boneblack.dtb.d.pre.tmp -nostdinc -Iinclude -Isrc -Itestcase-data -undef -D__DTS__ -x assembler-with-cpp -o am335x-boneblack.dtb.dts.tmp am335x-boneblack.dts
c. Führen Sie den Compiler selbst aus:
dtc -O dtb -o am335x-boneblack.dtb -b 0 -i src -d am335x-boneblack.dtb.d.dtc.tmp am335x-boneblack.dtb.dts.tmp
4. Am335x-Boneblack.dtb sollte auf der Boot-Partition neben dem Kernel abgelegt werden. Fügen Sie im Startskript für Barebox die folgende Zeile hinzu: "
global.bootm.oftree=/boot/am335x-boneblack.dtb
"
Auswahl eines Systems zum Einzug von gehandelten Belastungen.
Wie Sie wissen, gibt es keine Systeme ohne Fehler sowie die Analyse eines Multithread-Systems ohne Spuren. Es ist sehr praktisch, wenn diese Traces nicht einfach in der Konsole angezeigt werden, sondern mit etwas speziell dafür erstelltem gesammelt werden, damit sie nach Prozessen sortiert, Filter angewendet usw. werden können. Und ich kenne nur ein gutes System, das sowohl unter Host als auch unter Ziel einfach aufzubauen ist. Dies ist DLT. Wenn Sie noch nie davon gehört haben, spielt es keine Rolle. Alle Wissenslücken können leicht durch Lesen von
at.projects.genivi.org/wiki/display/PROJ/Diagnostic+Log+and+Trace geschlossen werden .
Dieses System besteht aus dlt-daemon und dlt-viewer. Wie der Name schon sagt, wird dlt-daemon auf dem Ziel und dlt-viewer auf dem Host ausgeführt. Zu all dem, zu Ihrer Binärdatei, von der wir Spuren sammeln möchten, müssen Sie die dlt lib verknüpfen.

Im Allgemeinen ist alles praktisch, wie man Spuren sammelt und analysiert, empfehle ich.
Ein Build-System schreiben.
Warum ein Build-System schreiben, weil Sie alles aus den Repositorys herunterladen, mit Ihren Händen erstellen und auf der Grundlage dieses Rootfs und Schleiers erstellen können, funktioniert der Controller. Aber einen solchen Trick in einem Monat zu wiederholen, wird schwieriger sein, und in zwei - das ist im Allgemeinen unmöglich. Auch hier müssen Sie sich daran erinnern, was, wo Sie platzieren, was Sie bauen und wie Sie beginnen sollen. Nachdem Sie zunächst viel Zeit aufgewendet haben, speichern Sie diese später und erhalten die Möglichkeit, bequem unter Host und Ziel zu erstellen. Das Build-System besteht aus einer Reihe von Skripten, die den Host zunächst auf den Build vorbereiten und Komponenten von Drittanbietern wie Buildroot, Mosquitto und DLT-Daemon aus ihren Repositorys herunterladen, erstellen und an ihren Speicherorten ablegen. Und dann können Sie den Build Ihres Projekts starten. Wenn der Build unter dem Host nicht schwierig ist, müssen Sie immer am Build unter dem Ziel basteln, und es wäre besser, wenn das Skript dies tut.
Buildroot kann so konfiguriert werden, dass es ein Post-Build-Skript aufruft, nachdem es rootfs gebildet hat, das in buildroot / output / target liegt. Dies gibt Ihnen eine großartige Gelegenheit, alles, was Sie brauchen, dort abzulegen. Und dann enthält das Dateisystem-Image bereits alles, was Sie zum Starten Ihres Systems benötigen.
Das Rezept ist ungefähr so:
- Sie müssen Ihre Binärdateien irgendwo in buildroot / output / target kopieren, z. B. in / opt / bin
- Wenn es Konfigurationen gibt, machen Sie dasselbe mit ihnen, nur in / opt / etc.
- Kopieren Sie Binärdateien von Drittanbietern. Für mich sind es Moskito, DLT-Daemon, deren Bibliotheken und Konfigurationen
- Um das System selbst beim Laden des Controllers zu starten, müssen Sie Ihre systemd-Dienste kopieren. Es ist besser, sie in Ihrem Ziel zu kombinieren und wieder zu aktivieren, indem Sie einen Symlink für mehrere Benutzer erstellen.
- Kopieren Sie die geänderte fstab (warum, ich werde es Ihnen später sagen)
Danach müssen Sie nur noch buildroot / output / images / rootfs.tar in den gewünschten Bereich der SD-Karte entpacken und die Stromversorgung einschalten.
build git repo: https://github.com/azhigaylo/build
Schreiben eines Kommunikationskerns.
Das Konzept ist so alt wie der Modbus selbst.
Jedes E / A-Gerät in einem Modbus-Netzwerk verfügt über (16-Bit-) Register zum Lesen, Lesen / Schreiben, in denen Daten gespeichert sind und über die diese Geräte gesteuert werden. Die Steuerung verfügt wiederum über Arrays aus diskreten (Status und Bytewert) und analogen Punkten (Status und Gleitkommawert), in denen der Status aller Parameter gespeichert wird.
Die Aufgabe des Kommunikationskerns ist also einfach: Sammeln Sie Daten von E / A-Geräten mithilfe des Modbus-Protokolls, ordnen Sie sie Controller-Punkten zu und gewähren Sie der oberen Ebene Zugriff auf diese Punkte. Und wenn Sie etwas verwalten müssen, ist alles in die andere Richtung - das logische Gerät (dazu später mehr) muss den Controller-Punkt abonniert haben, und das Schreiben in diesen Punkt initiiert die Übersetzung dieses Parameters in das physische Wasserausgabegerät.

Um die Daten irgendwie zu strukturieren und mit Geräten zu arbeiten, können Sie das Konzept eines logischen Geräts einführen, das den Status eines physischen Geräts in Ihrer Software anzeigt.
Ich habe auch beschlossen, die logischen Geräte in zwei Gruppen zu unterteilen:
- Standard (Widder-Module mit diskreter Ein- / Ausgabe), für die die Anzahl der Modbus-Register mit Daten im Voraus bekannt ist, und es reicht aus, nur die Controller-Punkte zu bestimmen, an denen diese Daten gespeichert werden sollen.
- Benutzergeräte, für sie ist es notwendig, die Zuordnung von Modbus-Registern zu Controller-Punkten unabhängig zu beschreiben.
Aus all diesen Gründen ist es logisch, eine Art Konfigurator für den Controller zu haben, egal ob es sich nur um eine JSON-Konfiguration oder ein selbst geschriebenes Tool handelt, das eine binäre Konfiguration generiert. Ich habe die zweite Option, weil es Ideen gab, einen Kommunikationskern so zu schreiben, dass er nicht nur auf dem Linux-Board, sondern auch auf Arduin mit FreeRtos problemlos ausgeführt werden kann, wodurch die PAL-Ebene in der Software geändert wird.
Im Konfigurator für jedes Gerät müssen Sie die Controller-Portnummer rs485, die Geräteadresse und den Controller-Punkt festlegen, an dem der Kommunikationsstatus mit dem Gerät angezeigt wird. Außerdem werden für jedes Standardgerät die Kanäle beschrieben und für ein Benutzergerät die Register den Punkten zugeordnet.


Eine solche Konfigurationsdatei, die alle erforderlichen Daten zum Aufbau des Modbus-Netzwerks enthält, ermöglicht es Ihnen, den Quellcode für das Projekt nicht zu ändern, wenn Sie Eingabe- / Ausgabegeräte hinzufügen / entfernen / ändern müssen. Es reicht aus, die Parameter im Konfigurator zu ändern und sie in der Konfigurationsdatei zu speichern.
Beim Start analysiert der Kommunikationskern die Konfiguration und erstellt auf seiner Basis Listen logischer Geräte für jeden rs485-Port des Controllers. Anschließend werden Threads an jedem Port erstellt und eine zyklische Abfrage physischer Geräte beginnt.
core git repo: https://github.com/azhigaylo/homebrain_core
Mqtt-Gateway schreiben.
Tatsächlich sind Ihre diskreten und analogen Controller-Punkte mit einer proprietären Schnittstelle für den Zugriff auf sie für niemanden von Interesse. Es gibt also nur einen Ausweg - mqtt. Ich denke, ich werde nicht übertreiben, wenn ich sage, dass dies derzeit das am häufigsten verwendete Protokoll für den Austausch kleiner Nachrichten ist. Außerdem ist es sehr einfach und verständlich zu verwenden. Als ich also Daten vom Controller übertragen musste, dachte ich nicht lange darüber nach, was ich verwenden sollte.

Weil Ich habe viele Parameter, dann gab es immer Verwirrungen in der Gateway-Konfigurationsdatei, in der die Zuordnung von Controller-Punkten zu mqtt-Gateway-Themen registriert wurde. Google half der Tabelle und schrieb einen CSV-Parser dieser Tabelle in die JSON-Konfigurationsdatei für das Gateway.
Gateway Git RepoParser Git RepoSchreibpunktmonitor.
Manchmal ist es sehr nützlich zu sehen, was mit den Controller-Punkten passiert. Dazu habe ich eine kleine Anwendung geschrieben, die direkt mit dem Kommunikationskern verbunden ist und den Status von diskreten und analogen Punkten liest. Ich bin ziemlich eng mit der Benutzeroberfläche, also konnte ich die Anwendung irgendwie in QML werfen. Es hat mit einem Knarren funktioniert. Sie können den Punkt zählen, Sie können ihn schreiben, aber ich brauche nicht mehr.
pointmonitor git repo: https://github.com/azhigaylo/pointmonitor
Mounten Sie das schreibgeschützte Dateisystem.
Normalerweise achten nur wenige Leute darauf, und selbst in Produktionsprojekten finden Sie Geräte, auf denen die Partition mit rootfs beschreibbar ist. Dies führt früher oder später zum Absturz eines der stabilsten Dateisysteme. Weil Da der Controller jederzeit ausgeschaltet werden kann, ist dies nur eine Frage der Zeit / des Falls. Um diese Wahrscheinlichkeit zu minimieren, müssen Sie ein wenig an fstab basteln und es vor dem Erstellen des rootfs-Images wie oben beschrieben dort ablegen. In fstab müssen Sie erstens das Dateisystem schreibgeschützt bereitstellen, und zweitens kann alles, was sich ändern kann, in tmpfs abgebildet werden.
Mein fstab ist das, es kann für Sie unterschiedlich sein:
/dev/root / auto ro 0 1 tmpfs /tmp tmpfs nodev,nosuid,size=50M 0 0 tmpfs /srv tmpfs nodev,size=50M 0 0 tmpfs /var/log tmpfs defaults,noatime,size=50M 0 0 tmpfs /var/tmp tmpfs defaults,noatime,size=50M 0 0 tmpfs /var/run tmpfs defaults,noatime,size=50M 0 0 tmpfs /var/lib tmpfs defaults,noatime,size=10M 0 0
Steuerkörper
Ein 3D-Drucker ist seit langem in den Masthead-Abschnitten für jeden kollektiven Landwirt enthalten. Leider habe ich ihn nicht, aber er ist in Arbeit. In letzter Zeit ist die Aufregung anderer Mitarbeiter für ihn verschwunden. Ich benutze dies, wenn ich alles drucke, was ich brauche und was nicht. Sie können davon überzeugt sein, indem Sie meinen vorherigen Beitrag lesen.
Wir zeichnen in FreeCAD, wir generieren den Gcode in Cura und wir erhalten einen Fall, ohne zu vergessen, Sitze für das Board, Ausschnitte für Steckverbinder und Kühlung und Hypotheken für Clips auf einer Din-Schiene zu machen.


Nun, das ist alles, jetzt haben wir eine Karte, Software auf einer SD-Karte und eine Hülle. Wir nehmen eine Datei (ich mache keine Witze) und verbinden alles miteinander, schließen die Stromversorgung, RS485-Kabel an und alles beginnt zu funktionieren. Und du hast gesagt, schwierig, schwierig ...