FreshRSS

🔒
❌ Über FreshRSS
Es gibt neue verfügbare Artikel. Klicken Sie, um die Seite zu aktualisieren.
Vor vorgesternIhre RSS-Feeds

JavaLand 2024: Chance statt Enttäuschung zum zehnjährigen Jubiläum

Von heise online

Dass die JavaLand 2024 nicht mehr im Phantasialand stattfindet, eröffnet der Community-Konferenz neue Möglichkeiten.

Vor kurzem ist die Bombe geplatzt: Die JavaLand 2024 [1] kann doch nicht wie geplant im Februar am gewohnten Ort stattfinden. Stattdessen wird sie das erste Mal seit ihrem Bestehen an eine neue Location umziehen. Im April wird sich die Java-Community nächstes Jahr nicht mehr im Freizeitpark, sondern am Nürburgring treffen. Wir sind uns sicher, dass diese Neuigkeiten bei vielen Community-Mitgliedern Fragen aufwerfen, allen voran: Warum geht ihr von dieser coolen Location weg? Wir möchten diesen Blogbeitrag nutzen, um unsere persönliche Sichtweise darzustellen, auch wenn die offizielle Pressemitteilung schon einige Fragen beantwortet [2]. Uns ist die Community wichtig und hier können wir etwas konkreter werden. Vor allem möchten wir Gerüchten vorbeugen.

Wie viele aus der Community fanden auch wir das Phantasialand als Location einen Lichtblick im Einheitsgrau der Hotel-Lobbys, Kongresszentren und Kinosäle (wobei die schon auch cool sind). Aber die Location war nicht der einzige Punkt, denn die JavaLand hat dank uns allen (Sprechern, Besuchern, Java User Groups, Aussteller ...) noch einiges mehr zu bieten und hebt sich positiv aus der Konferenzlandschaft ab. Diesen ganz eigenen Spirit empfinden wir bis heute als einmalig und wollen ihn als Mitglieder der Konferenzleitung auch in Zukunft sichern und weiter ausbauen.

Aber die Hürden, die JavaLand im Phantasialand durchzuführen, waren zuletzt zu hoch geworden. Es hatte sich bereits in den vergangenen Jahren gezeigt, dass das Event-Management des Phantasialand nicht in der Lage ist, eine JavaLand nach den Wünschen unserer Community durchzuführen. Leider haben die vielen Bemühungen nicht ausgereicht, um die problematischen Punkte zu klären. Das Phantasialand-Management hat nicht flexibler agiert. Vielmehr wurde die Situation für uns in der Planung und Durchführung der Konferenz jedes Jahr schwieriger. Nächstes Jahr hätten diese Punkte auch das erste Mal alle Besucher direkt betroffen. Wir hätten eine JavaLand im kühlen Februar ohne Nutzung der Fahrgeschäfte gehabt. Dazu kam, dass die Konferenzleitung auch die Preiserhöhungen (inklusive der Hotelpreise) nicht mehr sinnvoll abfangen konnte, sodass dem Rückgang beim Spirit eine deutliche Erhöhung der Kosten pro Besucher gegenübergestanden hätte. Wir möchten hier nicht noch konkreter werden und auch ein Bashing gegenüber dem Phantasialand vermeiden. Allerdings sind wir der Meinung, dass diese offene Begründung nötig ist, um Gerüchte oder Fehlinformationen zu vermeiden. Am Ende unterscheidet sich unsere Java Community zum Glück grundsätzlich von der Klientel, die sich das Phantasialand Event-Management offenbar als Kunden wünscht.

Das Ganze führt uns nun zur aktuellen Situation und der Bekanntmachung der großen Änderungen für die JavaLand 2024. Und das dann auch noch zum 10. Jubiläum. Wird es die gleiche Konferenz sein wie bisher? Ganz bestimmt nicht. Aber gerade wir als agile Entwickler wissen ja, Änderungen gehören zu unserem Alltag. Sie bringen auch immer Fortschritt und ganz neue Möglichkeiten. Aktuell gibt es viele Diskussionen in der Konferenzleitung, wie wir den Kern des JavaLand-Spirit an die neue Location mitnehmen und durch weitere Aspekte sinnvoll ergänzen können. Der Vorteil ist, dass der Nürburgring bereits einiges an Attraktionen zu bieten hat. Denkbar sind Rennen in E-Karts (uns ist auch ein gewisser Grad an Nachhaltigkeit wichtig) und es gibt zum Beispiel auch ein 3D Kino. Außerdem sprudeln bereits die Ideen, wie wir mit Ständen, Foodtrucks, großartigen Abend-Events mit Live-Musik und viele weiteren Attraktionen ein Festival erschaffen und aber auch das Themenpark-Feeling an den Ring holen können.

Hinzu kommt, dass die Location deutlich mehr Möglichkeiten für Community-Aktivitäten bietet. Daher möchten wir euch erneut aufrufen, Ideen für eines der Highlights der JavaLand, das Community-Programm einzureichen. Die Community-Aktivitäten reichen vom direkten Austausch in Diskussionsrunden über kleine Hands-On-Sessions, dem Netzwerken, die Durchführung der JavaLand4Kids bis zu sportlichen Aktivitäten. Das Joggen ist auf jeden Fall wieder dabei, aber vielleicht drehen wir diesmal auch ein paar schnelle Fahrrad-Runden auf dem Nürburgring. Wer mag, kann sich bei der Anreise der JavaLand Fahrrad-Sternenfahrt anschließen, wenn auch diesmal mit ein paar mehr Höhenmetern. Die im vergangenen Jahr erstmals angebotene Unkonferenz wird ebenfalls wieder am Vortag stattfinden. Und im normalen Vortragsprogramm wird es erstmals Deep-Dive-Sessions von fast zwei Stunden geben. All das wird die Black Mamba, die Taron und die anderen coolen Fahrgeschäfte nicht ersetzen können, aber euch wird garantiert nicht langweilig. Und jetzt ist es vielleicht auch leichter, der Chefin oder dem Chef den Besuch bei der JavaLand zu verkaufen.

Wir sind sehr froh über die Neuerungen und sehr gespannt auf die Möglichkeiten, die sich uns bieten werden. Die Planung der JavaLand-Konferenz, die zähen Monate mit den schwierigen Verhandlungen (und den trotzdem nur sehr eingeschränkten Möglichkeiten im Phantasialand) sowie die schwierige Suche nach Alternativen hat uns das erste Mal nicht mehr wirklich Spaß gemacht. Aber diese neue Location bietet nun wieder interessante Optionen, diese ganz besondere Konferenz noch ein Stück besser zu machen. Und hier bitten wir natürlich auch euch, die Java-Community, kreativ zu werden. Macht mit euren Vorschlägen zu den Community-Aktivitäten die JavaLand 2024 wieder zu einem ganz besonderen Erlebnis. Gerade die zehnte JavaLand möchten wir lieber an einem alternativen Ort mit neuen Aktivitäten und Ideen durchführen als unter den leider immer größer werdenden Einschränkungen im Phantasialand.


URL dieses Artikels:
https://www.heise.de/-9322819

Links in diesem Artikel:
[1] https://www.heise.de/news/JavaLand-Konferenz-aendert-den-Termin-und-zieht-zum-Nuerburgring-9317740.html
[2] https://www.javaland.eu/de/home/news/details/javaland-2024-neuer-termin-und-neue-location-call-for-papers-verlaengert/
[3] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 02. Oktober 2023 um 12:42

Java 21 ist eines der spannendsten Releases der letzten Jahre

Von heise online

(Bild: Natalia Hanin / Shutterstock.com)

Mit dem OpenJDK 21 ist gerade ein Release erschienen, für das Hersteller längeren Support (LTS) anbieten. Diese Version hat aber auch sonst einiges zu bieten.

Mit 15 JEPs (JDK Enhancement Proposals) bringt das OpenJDK 21 so vielen Themen wie lange nicht. Und es hält auch inhaltlich eine Menge interessanter Features für uns Java-Entwickler bereit. Einige Funktionen sind schon länger in Arbeit, darunter das Pattern Matching, die Virtual Threads, die Vector API oder auch die Foreign Function & Memory API. Während beim Pattern Matching und den Virtual Threads Teile finalisiert wurden, bleiben andere Aspekte weiterhin im Preview- oder auch Inkubator-Modus. Für Entwickler besonders spannend sind aber einige ganz neue Themen wie die String Templates, die "Unnamed Classes and Instance Main Methods" (beide zunächst als Preview dabei) und die Sequenced Collections

Pattern Matching ist jetzt produktiv einsetzbar

Beim Pattern Matching geht es darum, bestehende Strukturen mit Mustern abzugleichen, um komplizierte Fallunterscheidungen effizient und wartbar implementieren zu können. Es wird bereits seit einigen Jahren im Rahmen von Project Amber entwickelt. Bis zum letzten Release mit LTS-Support (OpenJDK 17) wurden zunächst nur Basis-Funktionen wie Switch Expressions, Sealed Classes, Records und Pattern Matching for instanceof abgeschlossen. Mit Java 21 kann es nun auch produktiv eingesetzt werden. Mit den Record Patterns und dem Pattern Matching for switch wurden zwei wichtige Bausteine finalisiert. Bei den Record Patterns handelt es sich um einen neuen Pattern Typ, der Records matched und gleichzeitig in ihre Bestandteile zerlegt (dekonstruiert), sodass direkt mit den Komponenten weitergearbeitet werden kann. Und mit Pattern Matching for switch werden alle bisherigen Funktionen zusammengebracht, sodass man in switch-Expressions nun neben den schon immer verfügbaren Constant Patterns auch Type- und Record Patterns inklusive der when-Clauses (früher Guarded Patterns genannt) einsetzen kann. Ganz frisch (in 21 als Preview eingeführt) sind die Unnamed Patterns. Dadurch lassen sich Platzhalter (der Unterstrich _) verwenden, wenn die Pattern Variablen nicht ausgewertet werden sollen. Das macht den Code kompakter, besser lesbar und weniger fehleranfällig (vermeidet toten Code). Dieses Konstrukt lässt sich auch in catch-Blöcken oder bei Lambda-Parametern als sogenannte Unnamed Variables einsetzen.

Virtual Threads machen Java zukunftssicher

Da sind sich viele Experten einig und zeigen ihre Begeisterung für eines der wichtigsten Features in der Geschichte von Java, das sich direkt in eine Reihe mit Generics, Lambda-Ausdrücken und dem Plattform-Modul-System einreiht. Die Virtual Threads erlauben eine viel größere Anzahl gleichzeitiger Threads. Sie haben besonders beim Ressourcenverbrauch die Nase vorn gegenüber den klassischen Plattform-Threads. Dadurch können viel mehr (theoretisch Millionen) der virtuellen Threads in einem Prozess gestartet werden, ohne gleich an die Speichergrenzen der VM zu stoßen. Das ermöglicht eine bessere Auslastung der CPU. Die meisten Java Entwickler werden allerdings nicht direkt mit nebenläufiger Programmierung und Virtual Threads in Berührung kommen. Sie profitieren trotzdem, weil Framework-Hersteller (Spring, Quarkus, ...) Virtual Threads unter der Haube einbauen werden. Das ermöglicht gerade bei Webanwendungen eine bessere Auslastung, weil mehr eingehende Requests von Nutzern gleichzeitig verarbeitet werden können. Die Bremse sind ohnehin IO-Zugriffe (z. B. auf die Datenbank). Da die Requests aber sehr günstig zu erzeugen und zu betreiben sind (geringerer Speicherverbrauch) und so viel mehr gleichzeitig verwaltet werden können, lassen sich die vorhandenen Ressourcen besser nutzen.

Im Umfeld der nun abgeschlossenen Virtual Threads gibt es noch zwei, erneut als Preview erschienene Funktionen, die Structured Concurrency und die Scoped Values. Letzteres ist eine bessere Alternative zu den ThreadLocal-Variablen. Und Structured Concurrency ermöglicht die Bearbeitung von mehreren parallelen Teilaufgaben auf eine besonders les- und wartbare Art und Weise.

Die kleineren Themen machen Java Entwickler glücklich

Einige der vom Funktionsumfang überschaubaren Features sind etwas überraschend im Release von Java 21 aufgetaucht. Besonders spannend sind die String Templates. Sie bringen nicht nur die lang ersehnte String Interpolation in die Java Welt. Die Implementierung ermöglicht in Zukunft sogar das einfache Erstellen eigener Template Prozessoren, die aus Texten mit Platzhaltern zum Beispiel JSON Objekte oder sichere Datenbankabfragen mit PreparedStatements erzeugen können.

Sequenced Collections bringen eine Handvoll neuer Methoden für Collections, deren Elemente in einer wohldefinierten Reihenfolge geordnet sind. Dazu zählen Lese- und Schreibzugriffe (inklusive Entfernen) auf das erste beziehungsweise letzte Element und das Umdrehen der Reihenfolge (reversed()). Dadurch wird das immer noch viel benutzte Collection Framework weiter aufgewertet.

Für Java-Einsteiger wird es in Zukunft auch leichter. Sie müssen zum Erstellen einer ausführbaren Klasse nicht mehr gleich die speziellen Konstrukte wie class, static, public, String[] args usw. verstehen. Mit dem "JEP 445: Unnamed Classes and Instance Main Methods (Preview)" kann man jetzt ausführbare main-Methoden kürzer und prägnanter definieren und sogar auf eine umschließende Klasse verzichten. In Kombination mit dem im JDK 11 veröffentlichten JEP "Launch Single-File Source-Code Programs" lassen sich sehr schlank kleine Java-Anwendungen in einer Textdatei mit einer simplen void main(){}-Methode von der Kommandozeile aufrufen. Und das kommt dann auch erfahrenen Java-Entwicklern zugute.

Was sonst noch passiert ist

Die Vector API ist ein Dauerläufer und taucht seit Java 16 regelmäßig in den Releases auf, diesmal als sechster Inkubator (Vorstufe von Preview). Es geht dabei um die Unterstützung der modernen Möglichkeiten von SIMD-Rechnerarchitekturen mit Vektorprozessoren. Single Instruction Multiple Data (SIMD) lässt mehrere Prozessoren gleichzeitig unterschiedliche Daten verarbeiten. Durch die Parallelisierung auf Hardware-Ebene verringert sich beim SIMD-Prinzip der Aufwand für rechenintensive Schleifen.

Auch schon seit einigen Versionen mit an Bord ist die Foreign Function & Memory API, diesmal im 3. Preview. Wer schon sehr lange in der Java-Welt unterwegs ist, wird das Java Native Interface (JNI) kennen. Damit kann nativer C-Code aus Java heraus aufgerufen werden. Der Ansatz ist aber relativ aufwändig und fragil. Die Foreign Function API bietet einen statisch typisierten, rein Java-basierten Zugriff auf nativen Code (C-Bibliotheken). Zusammen mit dem Foreign-Memory Access API kann diese Schnittstelle den bisher fehleranfälligen und langsamen Prozess der Anbindung einer nativen Bibliothek beträchtlich vereinfachen. Mit letzterer bekommen Java-Anwendungen die Möglichkeit, außerhalb des Heaps zusätzlichen Speicher zu allokieren. Ziel der neuen APIs ist es, den Implementierungsaufwand um 90 Prozent zu reduzieren und die Leistung um Faktor 4 bis 5 zu beschleunigen. Beide APIs sind seit dem JDK 14 beziehungsweise 16 im JDK zunächst einzeln und ab 18 als gemeinsamer Inkubator-JEP enthalten. Vermutlich wird sich dieses Feature langsam der Finalisierung nähern.

Bei den Garbage Collectors hat sich auch etwas getan. Der vor wenigen Jahren im OpenJDK 15 eingeführte ZGC (Scalable Low-Latency Garbage Collector) gehört zu einer neuen Generation. Das Ziel ist, große Datenmengen (TB von RAM) mit möglichst kurzen GC-Pausen (kleiner 10 ms) aufzuräumen und so die Anwendung nahezu immer antwortbereit zu halten. Bisher machte der ZGC keine Unterscheidung zwischen frischen und schon länger existierenden Objekten. Die Idee ist, dass Objekte, die bereits einen oder mehrere GC-Läufe überlebt haben, auch in Zukunft wahrscheinlich noch lange weiterleben werden. Diese werden dann in einen extra Bereich (Old Generation) verschoben und müssen so bei den Standard-Läufen nicht mehr verarbeitet werden. Das kann einen Schub bei der Performance einer Anwendung geben.

Es gibt noch einige weitere, für Entwickler nicht so relevante JEPs. Für die vielen Details lohnt auch ein Blick auf die Release Notes [3]. Änderungen am JDK (Java Klassenbibliothek) lassen sich zudem sehr schön über den Java Almanac [4] nachvollziehen. In dieser Übersicht finden sich unter anderem alle Neuerungen zu den String Templates und den Sequenced Collections. In der String-Klasse gab es auch kleine Erweiterungen: Beispielsweise wurde die Methode indexOf(String str, int beginIndex, int endIndex) eingeführt, die in einem bestimmten Bereich nach einem Teil-String sucht. Die Klassen StringBuffer und StringBuilder wurden jeweils um zwei ähnliche Methoden erweitert, die ein Zeichen oder eine Zeichenkette wiederholt mal an das bestehende Objekt anhängen: repeat(CharSequence, int). Die Klasse Character wurde wiederum um eine Vielzahl von Methoden erweitert, die prüfen, ob eine Unicode-Zeichen ein Emoji oder eine Variante davon darstellt. Java geht also auch hier mit der Zeit.

Fazit

Einen ausführlichen Überblick über das Java-21-Release findet sich im frisch erschienen iX-Artikel [5]. Durch die Finalisierung der Virtual Threads wird Java 21 in ein paar Jahren auf eine Stufe mit Java 5 (Generics), Java 8 (Lambdas, Stream-API) und Java 9 (Plattform Modul System) gestellt werden. Auch wenn sich das Potenzial dieser Idee noch nicht vollständig erfassen lässt, werden die virtuellen Threads die Implementierung von hochskalierbaren Server-Anwendungen in Zukunft stark vereinfachen. Aber Java 21 hält noch viele andere Highlights bereit. Beim Pattern Matching wurden das Kernstück (Pattern Matching for switch) sowie die Record Patterns finalisiert und die Unnamed Patterns als Preview eingeführt. Die String Templates (im Moment noch als Preview) und auch die Sequenced Collections erleichtern Java-Entwicklern das Leben. Das steigert schon jetzt die Vorfreude auf das nächste Release im März 2024.


URL dieses Artikels:
https://www.heise.de/-9309203

Links in diesem Artikel:
[1] https://java.bettercode.eu/
[2] https://java.bettercode.eu/index.php#programm
[3] https://jdk.java.net/21/release-notes
[4] https://javaalmanac.io/jdk/21/apidiff/17/
[5] https://www.heise.de/tests/Java-21-Version-mit-LTS-String-Templates-und-Virtual-Threads-vorgestellt-9302335.html
[6] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 19. September 2023 um 19:33

Community Day for Java Developers 2023

Von heise online

Open Elements

Der Community Day für Java Developers bietet am 16. Oktober Expertenvorträgen und Demos, die sich auf Java und Open Source konzentrieren.

Der iJUG e.V. [1] (Interessenverbund der Java User Groups) hat sich mit der Eclipse Foundation [2] zusammengetan, um im Rahmen der EclipseCon am 16. Oktober ein Tagesevent speziell für die (deutschsprachige) Java Community zu gestalten. Hier gibt es einen ganzen Tag voll Java Themen zu einem fairen Preis.

Der Community Day für Java Developers [3] auf der EclipseCon [4] ist ein ganztägiges Programm mit Expertenvorträgen, Demos und anregenden Sessions, die sich auf Java und die Entwicklung von Unternehmensanwendungen unter Verwendung von quelloffenen, herstellerunabhängigen Prozessen und Technologien konzentrieren. Die Open-Source-Projekte Jakarta EE [5], Adoptium [6] und MicroProfile [7] sowie andere von der Eclipse Foundation gehostete Java-Projekte und -Communities werden von weltweit führenden Java-Innovatoren wie Azul [8], Google [9], IBM [10], Microsoft [11], Open Elements [12], Oracle [13], Red Hat [14] und Tomitribe [15] unterstützt.

Mit 14 technischen Sessions, Networking und Verpflegung kostet das eintägige Event weniger als 50 Euro. Das wird durch die Zusammenarbeit zwischen der Eclipse Foundation, dem iJUG e.V. und den Sponsoren der EclipseCon ermöglicht.

Die Veranstaltung ist eine gute Gelegenheit, um herauszufinden, wie andere diese Technologien nutzen, sich mit Expertinnen und Experten aus der Community zu treffen, die wichtigsten Aspekte der Jakarta EE-, Adoptium- und MicroProfile-Technologien besser zu verstehen und Ideen mit innovativen Personen und Unternehmen des Ökosystems zu teilen.


URL dieses Artikels:
https://www.heise.de/-9192048

Links in diesem Artikel:
[1] https://www.ijug.eu/
[2] https://www.eclipse.org/
[3] https://www.eclipsecon.org/2023/java-community-day
[4] https://www.eclipsecon.org/2023
[5] https://jakarta.ee/
[6] https://adoptium.net/
[7] https://microprofile.io/
[8] https://www.azul.com/
[9] https://about.google/
[10] https://www.ibm.com/
[11] https://www.microsoft.com/
[12] https://open-elements.com/
[13] https://www.oracle.com/
[14] https://www.redhat.com/
[15] https://www.tomitribe.com/
[16] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 15. September 2023 um 15:48

Indiegogo, Kickstarter & Co – Die dunkle Seite des Crowdfunding

Von Dr. Michael Stal

(Bild: (c) Flickr)

Wer in Crowdfunding-Projekte investiert, muss sich den Risiken bewusst sein. Die Plattformen weisen meist jede Verantwortung von sich.

Crowdfunding hilft beim Anstoßen von Projekten, indem zahlreiche Unterstützer in ein Projekt investieren, an das sie glauben. Der Erfolg ist aber nicht garantiert, und es gilt auf Betrugsmaschen zu achten, zumal die Crowdfunding-Plattformen das Risiko auf die Investoren abwälzen.

Motivation

Ich möchte mit einer Erfolgsgeschichte beginnen:

Bambu Lab war völlig unbekannt, als das aufstrebende 3D-Drucker-Unternehmen seine X1/X1C-Kampagne über Kickstarter startete. Es sammelte schließlich fast 55 Millionen HK-$ von 5575 Unterstützern. In den folgenden Monaten stellte Bambu Lab die X1/X1C-Produktlinie fertig und schickte alle Perks an die Unterstützer. Dieser neue CoreXY 3D-Drucker erwies sich als revolutionäres, preisgekröntes und äußerst erfolgreiches Produkt, dem bald weitere Produkte wie der P1P und der P1S folgten. Es erübrigt sich zu sagen, dass Bambu Lab eine riesige Erfolgsgeschichte mit einem glücklichen Ende für das Crowdfunding-Unternehmen, den Kampagneninhaber und die Unterstützer war.

Einer der Vorteile von Crowdfunding lässt sich wie folgt zusammenfassen: Crowdfunding-Plattformen bringen innovative Kampagnenmacher und begeisterte Unterstützer zusammen. Sie ermöglichen es Start-ups und etablierten Unternehmen, Finanzmittel für innovative Produkte zu erhalten.

Im Nachhinein betrachtet, funktionieren nicht alle Kampagnen so gut. In einigen Fällen liefern die Werber kein Produkt, stellen nur ein unterdurchschnittliches Produkt her, haben kein Geld mehr oder entpuppen sich als Betrüger. Jahr für Jahr gehen auf diese Weise Millionen von US-Dollar verloren. Es ist nie vorhersehbar, ob ein Projekt erfolgreich sein wird, wie es bei Joint Ventures ebenfalls der Fall ist. Gründe für das Scheitern können die Undurchführbarkeit der Innovation, Budgetüberschreitungen, enorme Projektverzögerungen durch unglückliche Umstände wie Covid-19, zu niedrig angesetzte Kosten oder drastische Preiserhöhungen für notwendige Komponenten sein.

Lehren

Das Scheitern von Projekten lässt sich zwar nie vermeiden, aber Betrug schon.

Ein chinesischer Kampagnenbetreiber sammelte mit seiner Indiegogo-Kampagne für den kleinsten Mini-PC der Welt über eine Million US-Dollar ein, schaffte aber keine der versprochenen Perks. Nach einiger Zeit gab es sogar keine Kommunikation mehr zwischen den Unterstützern und dem Kampagnenbesitzer. Es schien, als sei der Eigentümer einfach von der Bildfläche verschwunden. Als die Unterstützer Indiegogo um Hilfe baten, fühlte sich das Crowdfunding-Unternehmen nicht zuständig. Sie sperrte einfach alle weiteren Beiträge, versah die Projektwebsite mit dem Hinweis "Diese Kampagne wird derzeit untersucht", lieferte aber weder die Ergebnisse der sogenannten Untersuchung noch eine Rückerstattung an die betrogenen Kunden.

Lektion 1: Crowdfunding-Unternehmen kümmern sich nicht (allzu sehr) um die Unterstützer. Sie verdienen Geld, indem sie eine Plattform für verschiedene Parteien bereitstellen, und behandeln die Geldgeber wie Risikokapitalgeber, die alle Risiken selbst tragen sollen.

Indiegogo und Kickstarter agieren im Grunde wie Wettbüros für Pferderennen, bei denen fast keine Transparenz über die Pferdebesitzer (auch Kampagnenbesitzer genannt) herrscht. Jeder Teilnehmer an solchen Szenarien trägt hohe Risiken, wobei das Wettbüro die einzige Ausnahme ist. Offensichtlich sind die Regeln zwischen den Kunden und der Crowdfunding-Plattform so definiert, dass die Bank (oder das Wettbüro) immer gewinnt.

Lektion 2: Wer sich an einer Crowdfunding-Kampagne beteiligen möchte, sollte mit einem Scheitern des Projekts und dem vollständigen Verlust der Beiträge leben können.

Jeder Unterstützer sollte sich dieser Realität bewusst sein. Er/sie könnte seinen/ihren gesamten Beitrag verlieren oder ein überbezahltes oder sogar nutzloses Produkt erhalten. Sicher, die Mehrheit der Kampagnen ist letztlich erfolgreich. Es gibt jedoch auch eine beträchtliche Anzahl von Kampagnen, die scheitern. Ich mache mir keine Sorgen um das Scheitern von Projekten trotz der enormen Anstrengungen der Kampagnenbetreiber. Das ist ein bekanntes und akzeptables Risiko, das die Geldgeber im Hinterkopf behalten sollten, wenn sie einen Beitrag leisten. Aber ich mache mir Sorgen um betrügerische Kampagnen, bei denen die Betreiber einfach die gesammelten Beiträge nehmen und verschwinden.

Lektion 3: Wer dringend ein bestimmtes Produkt benötigt, sollte sich nicht an einer Crowdfunding-Kampagne beteiligen, sondern es stattdessen bei etablierten Quellen kaufen.

Lektion 4: Derzeit gibt es keine Sicherheitsnetze für Unterstützer. Auch gibt es keine Transparenz oder Rechenschaftspflicht gegenüber den Kampagnenbetreibern. Eine Kampagne gleicht einem Spiel oder einer Wette auf die Zukunft, ohne ausreichende Transparenz in Bezug auf die Eigentümer der Kampagne.

Lektion 5: Man sollte nicht den Videos und Dokumenten trauen, die von Kampagnenbetreibern bereitgestellt werden. Diese Informationen sollte man als eine reine Marketing- und Werbekampagne betrachten und niemals irgendwelchen Versprechungen trauen, vor allem nicht solchen, die unrealistisch oder sehr, sehr schwierig zu erfüllen scheinen. Sätze wie "das weltweit erste", "das weltweit schnellste" oder "das weltweit kleinste" sollten die Unterstützer skeptisch machen.

Mögliche Gegenmaßnahmen der Crowdfunding-Plattform

Was könnte man tun, um solche Situationen zu vermeiden? Oder ist die Crowdfunding-Plattform von Natur aus nicht in der Lage, die Unterstützer zu schützen?

Eigentlich sollte es eine Art Vertrauensverhältnis zwischen allen Akteuren im Spiel geben – ja, es ist ein Spiel beziehungsweise eine Wette! Um das richtige Maß an Vertrauen zu erreichen, muss ein Crowdfunding-Unternehmen folgende Dienstleistungen anbieten:

  • Persönliche Identifizierung aller Kampagnenbesitzer mit offiziellen und legalen Dokumenten wie Pässen, Führerscheinen, Wohnorten. Dies ermöglicht es Unternehmen wie Indiegogo oder Kickstarter, mit den Kampagneninhabern in Kontakt zu bleiben und sie aufzuspüren. Natürlich können Pässe und andere Dokumente gefälscht werden, aber das erfordert einen erheblichen kriminellen Aufwand.
  • Transparenz: Wenn wir bestehende Kampagnen analysieren, ist mangelnde Transparenz eines der größten Probleme. Mit "mangelnder Transparenz" meine ich die Tatsache, dass die Geldgeber oft fast nichts über die Eigentümer der Kampagne wissen. Das hängt mit dem vorherigen Aspekt zusammen: Während die Geldgeber bei Kreditkartenzahlungen garantieren müssen, dass sie vertrauenswürdig sind (was von den Kreditkartenunternehmen überprüft wird), erhalten sie im Gegenzug nur eine winzige Menge an Informationen über die Kampagnenbesitzer. Moment mal! Ich zahle meinen Beitrag an Personen, die größtenteils anonym sind (d. h. sich hinter einer Kampagnen-Website verstecken)? Die Antwort lautet leider ja. Es reicht nicht aus, wenn nur das Crowdfunding-Unternehmen über detaillierte Informationen über die Eigentümer der Kampagne verfügt.
  • Due-Diligence-Maßnahmen würden erfordern, dass ein Crowdfunding-Unternehmen technisch überprüft, ob eine Kampagne bzw. ein Projekt durchführbar ist. Zu diesem Zweck können sie Experten auf dem jeweiligen Gebiet einstellen, um die Behauptungen der Kampagneninhaber zu überprüfen. Darüber hinaus sollten sie den Hintergrund der Kampagnenbesitzer, seien es Unternehmen oder Einzelpersonen, überprüfen. Wenn ein erfolgreiches Unternehmen wie Anker als Eigentümer der Kampagne fungiert, ist die Wahrscheinlichkeit, dass die Backer die angebotenen Vergünstigungen und Belohnungen erhalten, wesentlich höher. Ist der Initiator der Kampagne hingegen unbekannt, ist das Risiko deutlich höher. Wenn man über Kampagnen und ihre Urheber nachdenkt, sollte man auch an deren Verantwortlichkeit denken.
  • Kontrolle und Ausgewogenheit: schrittweise Überweisung der Beiträge anstelle einer vollständigen Zahlung auf einmal. Dies könnte etwas schwierig zu erreichen sein, da von den Kampagneninhabern sicherlich einige Vorabinvestitionen verlangt werden. Dennoch würde ich in diesem Zusammenhang eher die Haltung einer Bank (Crowdfunding-Plattform) und eines Kreditnehmers (Kampagnenbesitzer) erwarten. In jedem Schritt wie Prototyping, Testen, endgültiges Produktdesign, Herstellung und Auslieferung sollte das Crowdfunding-Unternehmen von den Kampagneninhabern Nachweise darüber verlangen, was sie mit den Crowdfunding-Investitionen bisher getan und erreicht haben. Für das Prototyping wird zum Beispiel nur ein kleinerer Geldbetrag benötigt. Wenn sie einen erfolgreichen Prototyp entwickelt haben, können sie mit der Fertigstellung des Produkts fortfahren. Wenn das Produkt fertig ist, geht es weiter mit der Herstellung. Bei jedem Schritt erhalten sie einen vorher festgelegten Prozentsatz der Finanzierung. Darüber hinaus müssen die Kampagneninhaber einen konkreten Zeitplan für alle ihre Aktivitäten vorlegen. Wenn sich ein Schritt verzögert, können keine weiteren Gelder erhalten werden, bis der Schritt abgeschlossen ist. Eine Art Ampel auf der Projektwebsite könnte den aktuellen Risikograd einer Kampagne darstellen.
  • Lieferung: Für jedes Projekt müssen die Kampagneninhaber nachweisen, dass sie die Vergünstigungen und Belohnungen tatsächlich an ihre Unterstützer versandt haben, indem sie entsprechende Dokumente des Lieferdienstes vorlegen. Meiner Erfahrung nach haben einige Kampagnenbetreiber die Vergünstigungen als versandt gekennzeichnet, ohne wirklich etwas zu versenden.
  • Kein Verkauf über andere Kanäle: Bei einigen Kampagnen begannen die Entwickler von Produkten bzw. Lösungen, ihre Produkte oder Lösungen über ihre Websites zu verkaufen, bevor einige Unterstützer ihre Vergünstigungen überhaupt erhalten hatten. Der Vertrag zwischen Unterstützern und Crowdsourcing-Plattformen sollte diese Möglichkeit definitiv ausschließen. Wenn Geldgeber über eine Crowdfunding-Kampagne Geld für die Produktentwicklung ausgeben, müssen sie die ersten sein, die die Produkte und die freigeschalteten Belohnungen erhalten. Darüber hinaus waren einige der verkauften Produkte deutlich billiger als der angegebene UVP. Das sieht nach Betrug aus, riecht nach Betrug und ist Betrug. In solchen Fällen würde ich erwarten, dass die Kampagnenbetreiber Strafen an die Unterstützer zahlen müssen.

Eigene Gegenmaßnahmen

Für Backer bzw. Sponsoren einer Crowdfunding-Kampagne existieren aufgrund der beschriebenen Tatsachen zurzeit nur wenige Möglichkeiten, Risiken zu vermeiden. Eine offensichtliche, wenn auch radikale Option wäre, einfach nicht an Crowdfunding-Kampagnen teilzunehmen. Würden alle Nutzer so verfahren, gingen allerdings Anbieter wie Kickstarter in kürzester Zeit pleite. Zudem hätten die ehrlichen, kleinen Kampagnenbetreiber das Nachsehen, die ohne diese Geldquelle ihre Projekte nicht umsetzen könnten.

Daher ist das erste Gebot, sich über den jeweiligen Kampagnenbetreiber detaillierte Informationen zu beschaffen. Natürlich hat diese Informationsakquise ihre Grenzen. Ist der Kampagnenbetreiber eine renommierte, bekannte Firma, die bereits seit Längerem im Geschäft ist und gute Produkte auf den Markt bringt? Falls ja, dürfte das Risiko erheblich geringer sein als bei "dubiosen" oder mehr oder weniger "anonymen" Geschäftspartnern. Inzwischen nutzen auch renommierte Unternehmen zunehmend die Möglichkeit des Crowdfunding.

Eine weitere Möglichkeit besteht darin, sich auf dem Markt nach ähnlichen Produkten umzusehen. Nicht jedes als innovativ angepriesenes Produkt ist es wirklich. Gibt es bereits stark verwandte Alternativen, sollte man besser zu diesen greifen. Es hat insbesondere Vorteile, Produkte von einem Shop zu beziehen, wenn Käufe dort abgesichert sind wie bei Zahlung über Paypal oder Kreditkarte der Fall.

Fast jedes über Kickstarter oder Indiegogo erworbene Produkt ist nach Beendigung der Kampagne über Stores verfügbar, wenn auch zu höheren Preisen. Die Ersparnis durch Finanzierung einer Kampagne gegenüber dem UVP kann schon einiges ausmachen. In manchen Fallen könnte sich ein Abwarten trotzdem vor allem lohnen, wenn die Differenz zwischen Crowdfunding-Preis und Endpreis eher marginal ist. Abwarten hat auch den Vorteil, dass relativ zeitnah nach Produktveröffentlichungen in der Regel auch einige Produktreviews folgen, denen Interessierte die Vorteile und Nachteile des Produkts entnehmen können. Bei Crowdfunding kauft man schließlich die Katze im Sack.

Teilweise finden sich bei der Websuche auch Bewertungen von Kampagnen, bei denen zum Teil Experten ihre Einschätzung verlautbaren. Diese Quellen erweisen sich oft als sehr hilfreich.

Crowdfunding-Sponsoren sollten sich nicht von virtuellen Demo-Videos oder Lobpreisungen des Anbieters mit Superlativen täuschen lassen. Zeigt ein Demovideo nur das grafisch simulierte Produkt, kann das zwar die einzige Option des Herstellers sein, aber auch ein bewusst produziertes Fake. Beispielsweise hat eine Kampagne für 3D-Drucker den Druckkopf in unterschiedlichen Varianten gezeigt, wovon aber bei den angebotenen Perks nie die Rede war. Aber auch bei der Illustration echter Prototypen ist Vorsicht geboten. Dahinter kann sich schließlich Dummy-Funktionalität verbergen. Stutzig sollten Interessierte werden, wenn das Produkt nie im Detail erscheint. Gehen aus der Beschreibung technische Spezifikationen und die Funktionsweise detailliert hervor, so lässt es sich besser einschätzen als bei vagen, lückenhaften, unrealistischen oder schwammigen Aussagen.

Wie bereits erwähnt, sollten Geldgeber ihre eigene Risikobereitschaft unter die Lupe nehmen. Handelt es sich um höhere Geldbeträge, deren Verlust sehr schmerzhaft wäre, sollte man von einer Kampagne Abstand nehmen. Das ist zugegebenermaßen schwer, weil sich Kampagnen unseren instinktiven Hang nach Vergünstigungen und coolen Gadgets zunutze machen. Es geht darum, unsere Entscheidungen bewusst und vernünftig zu treffen. Eine Nacht darüber zu schlafen, ist hier immer die bessere Option, auch wenn dann statt den Super-Early-Bird-Angeboten nur noch Early-Bird-Angebote übrigbleiben. Es empfiehlt sich, nicht gleich zu dem eigentlichen Produkt alles mögliche Zubehör mitzubestellen. Ist das Projekt erfolgreich, lässt sich Zubehör auch im Nachhinein bestellen. Dadurch bleibt der eingesetzte Geld- beziehungsweise Wettbetrag geringer.

Fazit

Einige mögen argumentieren, dass all diese Maßnahmen die Freiheit der Kampagnenbesitzer einschränken. In dieser Hinsicht haben sie recht. Allerdings besteht derzeit ein Ungleichgewicht zwischen Geldgebern, Kampagneninitiatoren und Crowdfunding-Plattformen, sodass die meisten Risiken bei den Geldgebern liegen. Daher erscheint es mehr als fair, diese Risiken unter allen Beteiligten aufzuteilen. Ich bin der festen Überzeugung, dass sich Crowdfunding zu einer Sackgasse entwickelt, wenn Unternehmen wie Indiegogo weiterhin alle Lasten auf die Unterstützer abwälzen, sich nicht um Betrug kümmern, sich weigern, Sicherheitsnetze zu schaffen, oder die hohe Intransparenz beibehalten. Wenn sie jedoch alle oder zumindest einige der oben genannten Maßnahmen umsetzen, wird sich dies eindeutig als ein Win/Win/Win-Szenario herausstellen.


URL dieses Artikels:
https://www.heise.de/-9297529

Links in diesem Artikel:
[1] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 07. September 2023 um 18:58

Edge AI: Künstliche Intelligenz auf eingebetteten Systemen nutzen

Von Dr. Michael Stal
Chip auf Mainboard

(Bild: raigvi / Shutterstock)

Eine Artikelserie führt in die Grundlagen von Edge AI ein und zeigt, wie sich künstliche neuronale Netze auf eingebetteten System ausführen lassen.

Wenn Softwareentwicklerinnen und Softwareentwickler von Artificial Intelligence (AI) und Machine Learning (ML) sprechen, meinen sie überwiegend künstliche neuronale Netze (KNN), deren Training und Inferenz vorzugsweise auf leistungsfähiger Enterprise-Hardware erfolgt. Dank Werkzeugen wie TensorFlow Lite (Micro) und Edge Impulse ist es heute möglich, zumindest die Inferenz eines neuronalen Netzes auch auf eingebetteten Systemen mit beschränkten Ressourcen durchzuführen. Dies hat den Charme, dass die Verarbeitung von Daten dort stattfinden kann, wo die Daten auch anfallen. Beispiele hierfür umfassen autonomes Fahren und die Automatisierungstechnik.

In einer dreiteiligen Artikelserie bespreche ich ab dem 18. August 2023 zunächst wichtige KI-Grundlagen (Teil 1), danach die Arbeit mit TensorFlow Lite (Teil 2), und zu guter Letzt die Anwendung des MLOps-Online-Werkzeugs Edge Impulse (Teil 3). Im dritten Teil kommt außerdem der KI-gestützte Entwicklerassistent GitHub Copilot zur Sprache, der das Entwickeln eingebetteter Software erlaubt.

Ziel dieser Rundreise ist es, interessierte Leserinnen und Leser mit KI-Technologien und Werkzeugen für eingebettete Systeme vertraut zu machen, sodass sie eigene Experimente durchführen können.


URL dieses Artikels:
https://www.heise.de/-9234664

Links in diesem Artikel:
[1] mailto:map@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 17. August 2023 um 15:00

Java ohne Kopfschmerzen: Distributionen und Support jenseits von Oracle

Von heise online
Logo von Softwarekonzern Oracle

(Bild: Sundry Photography/Shutterstock.com)

Es gibt nicht nur einen Anbieter für Java-Distributionen und Support. Gartner hat in einem Report die Optionen analysiert, und Oracle schneidet nicht gut ab.

Für die meisten Unternehmen gehören sowohl Java als Programmiersprache als auch die JVM als Laufzeitumgebung zur kritischen Infrastruktur, auf der ein großer Teil unserer digitalen Welt aufgebaut ist. Da für die kritische Infrastruktur im Enterprise-Umfeld immer geraten wird, über passende Support-Möglichkeiten zu verfügen, besitzen viele Firmen einen kommerziellen Support-Vertrag für Java. Diese Verträge wurden historisch oft mit Oracle geschlossen, da das Unternehmen lange Zeit der prominenteste Anbieter für Java-Distributionen war. Da sich aber in den letzten Jahren viel in diesem Bereich getan hat, stellt sich die Frage, ob Oracle hier noch immer der beste Partner für den kommerziellen Support von Java ist.

Diversität auch in der Laufzeitumgebung

In vielen Bereichen der heutigen Welt ist Diversität ein wichtiges Thema, da hierdurch neue Ansichten, Lösungen und Möglichkeiten entstehen. Auch im Bereich der Java-Laufzeitumgebungen hat sich hier in den letzten Jahren einiges getan. Die Zeit, in der Entwicklerinnen und Entwickler Java prinzipiell von Oracle heruntergeladen haben, da es der Platzhirsch bei Java-Distributionen war, ist lange vorbei. Durch die fortschreitende Beliebtheit von Open Source arbeiten mehr und mehr Firmen am OpenJDK [1] mit, der quelloffenen Implementierung der Java Standard Edition. Da auch die Distributionen von Oracle aus diesen Quellen gebaut werden, kann man somit auch problemlos zu Alternativen greifen. Dazu kommt, dass durch das Java Test Compatibility Kit (TCK) viele der Laufzeitumgebungen auf ihre Kompatibilität zum Standard hin überprüft werden.

Eclipse hat einen Marketplace eröffnet [2], in dem alle TCK und AQAvit verifizierten beziehungsweise lizenzierten Java-Laufzeitumgebungen zum Download angeboten werden. Neben verschiedenen Builds von Firmen wie Microsoft oder Azul tut sich hier vor allem Eclipse Temurin [3] hervor, das als einzige Java Distribution eine herstellerunabhängige Variante ist. Verantwortlich ist die Eclipse-Adoptium-Arbeitsgruppe, der Firmen wie Microsoft [4], Red Hat [5], Google [6] und Open Elements [7] angehören. Mit über 200 Millionen Downloads [8] gibt es auch keine andere Java-Distribution, die aufgrund ihrer Zahlen auch nur ansatzweise an die Verbreitung von Eclipse Temurin herankommt. Dies unterstreicht ein aktueller Gartner-Bericht [9], laut dem 2026 über 80 Prozent aller Java Anwendungen voraussichtlich nicht auf einer Oracle-Distribution laufen werden. Eclipse Temurin macht hier am Ende sicherlich das größte Stück des Kuchens aus.

Java-Support

Neben der Analyse verschiedener Distributionen hat Gartner die verschiedenen Möglichkeiten der kommerziellen Support-Optionen für Java untersucht. Hierbei hat vor allem der Oracle-Support nicht wirklich gut abgeschnitten:

Oracle hat erneut die Lizenzregeln für seine Java-Distributionen geändert. Am 23. Januar 2023 führte das Unternehmen eine neue Lizenzmetrik ein, die SE Universal Subscription [10]. Das kontroverse Preismodell zieht als Basis die Gesamtzahl der Kundenmitarbeiter heran und nicht die Anzahl der Mitarbeiter, die die Software nutzen. Möglicherweise versucht Oracle so, dass Kunden keine anderen Support-Modelle für Java in Erwägung ziehen. Für Kunden führt das in vielen Fällen dazu, dass die Support-Kosten für Java durch die Decke gehen. Laut Gartner entstehen hier für die meisten Organisationen zwei- bis fünfmal so hohe Kosten. Dazu kommt natürlich, dass man durch einen kommerziellen Support bei Oracle nur Support für die Oracle-Distribution erhält und nicht etwa für das immer beliebter werdende Eclipse Temurin. Vielleicht ist daher genau jetzt der richtige Zeitpunkt, sich einmal nach alternativen Angeboten für Java Support umzuschauen.

Natürlich haben Organisationen wie Azul oder auch die Arbeitsgruppe von Eclipse Adoptium auf diese Ereignisse reagiert. Mike Milinkovich, der Executive Director der Eclipse Foundation [11], kommentierte das Ganze wie folgt auf X / Twitter:

(Bild: Twitter / X)


Aber neben diesem Kommentar ließ Adoptium auch Taten sprechen und hat eine Seite für kommerziellen Support für Eclipse Temurin [12] eingerichtet. Auf dieser wird mit Red Hat, IBM und Open Elements gleich durch drei Experten der Branche Support für Eclipse Temurin angeboten. Hervorzuheben ist hierbei für den deutschsprachigen Raum Open Elements, da diese mit ihrem "Support & Care"-Paket [13] nicht nur aktiv Temurin als Open-Source-Projekt fördern, sondern auch Support in deutscher Sprache anbieten.

Wie man sehen kann, ist auch das Angebot an Support-Optionen für die Java Laufzeitumgebung in den letzten Jahren deutlich diverser geworden. Neben dem Angebot von Oracle gibt es nun verschiedene Möglichkeiten, die oft deutlich besser auf die eigenen Anforderungen zugeschnitten sind. Natürlich bedeutet das auch, dass jede Firma über den Tellerrand schauen und Alternativen zum bereits vor Jahren abgeschlossenen Oracle-Support begutachten und bewerten muss. Für Firmen, die bisher über keinen Support-Vertrag verfügen, eignen sich einige der Angebote vielleicht deutlich eher, als direkt mit dem Riesen Oracle einen Vertrag zu schließen. Aber auch das Angebot von Oracle hat seine Berechtigung und wird für einige Firmen das passende sein. Daher will ich hier nicht ein Angebot als Gewinner darstellen, sondern die Vielfalt der Möglichkeiten dank Firmen wie IBM, Red Hat, Azul, Open Elements und natürlich Oracle als Gewinn für die gesamte Java Community aufzeigen.


URL dieses Artikels:
https://www.heise.de/-9232113

Links in diesem Artikel:
[1] https://openjdk.org/
[2] https://adoptium.net/marketplace/
[3] https://adoptium.net/de/
[4] https://www.microsoft.com/openjdk
[5] https://www.redhat.com
[6] https://cloud.google.com/java
[7] https://open-elements.com/
[8] https://dash.adoptium.net/
[9] https://www.gartner.com/en/documents/4540799
[10] https://www.oracle.com/us/corporate/pricing/price-lists/java-se-subscription-pricelist-5028356.pdf
[11] https://www.eclipse.org
[12] https://adoptium.net/temurin/commercial-support/
[13] https://open-elements.com/temurin-support/
[14] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 03. August 2023 um 12:53

Gib mir den REST - Teil 2: Der Client

Von Dr. Michael Stal

Die Verbindung von eingebetteten Systemen und Servern kann über REST-Kommunikation erfolgen

(Bild: pixabay.com)

Wie kommuniziert ein Arduino-Board serverseitig mit einer REST-API, um Sensor-Messungen zu speichern? Nach dem Server in Teil 1 steht die Client-Seite an.

Arduino-Boards oder andere Microcontroller-Boards beziehungsweise eingebettete Systeme oder Einplatinencomputer können mit einer REST-Anwendung kommunizieren, wenn sie einen WiFi- oder Ethernet-Anschluss integrieren. Da ein typischer Anwendungsfall wie der hier vorgestellte überwiegend Messungen mit Sensoren durchführt, erweist eine Echtzeituhr (RTC) als Vorteil. Dadurch lassen sich zusätzlich zu den Messdaten Zeitstempel (Datum und Zeit) hinzufügen, die später eine historische Analyse ermöglichen, etwa den Verlauf der Temperatur über einen bestimmten Zeitraum.

Auch wenn hier vom Arduino Giga die Rede ist, beschränkt sich die Anwendung keineswegs nur auf dieses Board, sondern lässt sich relativ leicht für andere Arduino-, STM- oder ESP-Boards anpassen, für die funktional ähnliche Bibliotheken wie WiFi, WiFiUdp und HTTPClient in der Arduino IDE oder in Visual Studio Code mit PlatformIO-Plug-in bereitstehen.

Notwendig ist ein Sensor von Bosch Sensortec aus der BME-Familie (BME68x, BME58x, BME38x, BME28x), den Maker über I2C oder SPI anschließen. Für das Beispiel kam ein BME688 zum Einsatz, den es als Breakout-Board von verschiedenen Herstellern wie Pomoroni oder Adafruit gibt. Wer möchte, kann auch ein Bosch Development Kit kaufen. Dieses Board besteht aus einem BME688-Adapter, der huckepack auf einem Adafruit Huzzah32 Feather Board (ESP32) sitzt. Das schlägt mit rund 100 Euro zu Buche, hat aber den Charme, sich mittels der kostenlosen BME-AI-Studio-Software trainieren zu lassen. Der Sensor lernt dabei, über ein neuronales Netz verschiedene Gasmoleküle in der Luft zu erkennen, wie Kaffee, CO₂ oder Chlor. Er ermittelt für die Moleküle in der Luft Widerstände in Ohm und kann über die elektrische Charakteristik Gase klassifizieren. Diese spezifischen ML-Trainings sind mit Breakout-Boards freilich nicht möglich – der Anwender erfährt dort nur den Widerstand des Gases ohne Zuordnung zu einem konkreten Molekül. Dafür kosten die einfachen Boards auch nur zwischen 20 und 30 Euro.

Wie bereits im ersten Teil [1] erwähnt, findet sich der Quellcode für die Beispiele in dem GitHub Repository [2].

Ein Hinweis vorab: Als mögliche Alternative für die hier vorgestellte Integration über eine RESTful-Architektur käme beispielsweise der Einsatz von MQTT infrage, das eine ereignis- beziehungsweise nachrichtenorientierte Kommunikation zwischen Client und Server ermöglicht. In vielen Fällen, vielleicht auch für den hier vorliegenden, ist MQTT eine sehr gute Option. Allerdings fokussieren sich die beiden Artikelteile speziell darauf, Kommunikation und Backend-Integration über REST-APIs zu veranschaulichen. Ein vom Backend betriebener Microservice stellt schließlich typischerweise eine REST-API bereit.

Das Hardware-Setup

In der konkreten Schaltung sind die folgenden Verbindungen notwendig:

Arduino ........ BME688

3.3V ............ Vin

GND ............. GND

SCL ............. SCK

SDA ............. SDI

Folgendes Fritzing-Diagramm veranschaulicht dies:

Die Verbindung des BME688-Sensors und dem Arduino läuft über I2C oder SPI. Im vorliegenden Fall ist I2C das Mittel der Wahl

Die Arduino-Anwendung

Beim Entwickeln der Arduino-Software sind folgende Verantwortlichkeiten zu beachten:

Initiales Setup:

  • Verbindung zum WiFi-Netz aufbauen
  • Über NTP-Server die aktuelle Zeit einlesen und die Echtzeituhr (RTC) einstellen
  • Verbindung zum I2C-Sensor BME688 aufbauen

Kontinuierliche Loop:

  • Messergebnisse vom BME688 auslesen
  • Lokale Zeit über RTC ermitteln
  • JSON-Nachricht zusammenbauen
  • Mit REST-Server über WiFi/HTTP verbinden
  • POST-Nachricht schicken
  • Prüfen, ob die Paketsendung erfolgreich war

Nebenbei soll der Sketch Informationen über den seriellen Monitor zu Test- und Beobachtungszwecken ausgeben.

Verbindung zum WLAN

Der Arduino-Sketch erwartet im selben Verzeichnis eine Datei arduino_secrets.h, die Definitionen für das gewünschte WLAN enthalten, konkret die SSID und den WLAN-Key. Für die Nutzung des Arduino-WiFis bedarf es einer entsprechenden WiFi-Bibliothek, deren Header wir inkludieren, zum Beispiel: #include <WiFi.h>. Zusätzlich benötigen wir die Bibliothek ArduinoHttpClient, die wir über den Library Manager der Arduino IDE oder VS Code & PlatformIO installieren.

Den Verbindungsaufbau zum WLAN übernimmt nachfolgender Code:


void setup() {
  // Seriellen Stream starten
  Serial.begin(9600);

  // Verbindungsaufbau WiFi
  while (status != WL_CONNECTED) {
    Serial.print("Versuche Verbindungsaufbau zum WLAN-Netz: ");
    Serial.println(ssid);                   // print the network name (SSID);

    // Verbinden mit WPA/WPA2 Netzwerk:
    status = WiFi.begin(ssid, pass);
  }

  // Name des WLANs nach erfolgtem Verbindungsaufbau:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
NTP Protokoll

Anschließend soll der Zugriff auf einen NTP-Server zum Einstellen der Echtzeituhr verhelfen.

Beim Giga R1 Board sind dazu folgende Header-Dateien notwendig:

#include <WiFiUdp.h>      // zum Versenden von NTP-Paketen notwendig
#include <mbed_mktime.h>

Das schaut auf anderen Boards natürlich anders aus und wäre diesbezüglich zu ändern.

Der eigentliche Code für das Setzen der Echtzeituhr befindet sich in der Methode setNtpTime(), die ihrerseits eine UDP-Verbindung mit einem lokalen Port öffnet, ein Anfragepaket an den gewünschten Zeitserver verschickt (sendNTPacket()), um danach die Antwort über parseNtpPacket() zu empfangen, zu verarbeiten und die Echtzeituhr mit der aktuellen Zeit einzustellen. Hat dies erfolgreich geklappt, lässt sich fortan über die Methode getLocalTime() stets die aktuelle Zeit aus der Echtzeituhr auslesen. Zurückgeliefert wird jeweils ein Datetime-String, der sich aus Datum und Zeit zusammensetzt: „2023-06-05 12:31:45“.

// NTP-Anfrage senden, Antwort erhalten und parsen
void setNtpTime()
{
    status = WL_IDLE_STATUS;
    Udp.begin(localPort);
    sendNTPpacket(timeServer);
    delay(1000);
    parseNtpPacket();
}

// Rufe einen Zeitserver auf 
unsigned long sendNTPpacket(const char * address)
{
    memset(packetBuffer, 0, NTP_PACKET_SIZE);
    packetBuffer[0] = 0b11100011; // LI, Version, Modus
    packetBuffer[1] = 0; // Stratum, Art der Uhr
    packetBuffer[2] = 6; // Abfrageintervall
    packetBuffer[3] = 0xEC; // Präzision der Uhr
    // 8 Bytes von Nullen für Root Delay & Root Dispersion
    packetBuffer[12] = 49;
    packetBuffer[13] = 0x4E;
    packetBuffer[14] = 49;
    packetBuffer[15] = 52;

    Udp.beginPacket(address, 123); // NTP Aufrufe erfolgen über Port 123
    Udp.write(packetBuffer, NTP_PACKET_SIZE);
    Udp.endPacket();
}

// Hier wird das NTP-Antwortobjekt empfangen und geparst:
unsigned long parseNtpPacket()
{
    if (!Udp.parsePacket())
        return 0;

    Udp.read(packetBuffer, NTP_PACKET_SIZE); // Paket vom NTP-Server empfangen
    const unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    const unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    const unsigned long secsSince1900 = highWord << 16 | lowWord;
    constexpr unsigned long seventyYears = 2208988800UL;
    const unsigned long epoch = secsSince1900 - seventyYears;
    set_time(epoch);

// Folgende ausführliche Beschreibung lässt sich ausgeben,
// sobald man DETAILS definiert
#if defined(DETAILS)
    Serial.print("Sekunden seit Jan 1 1900 = ");
    Serial.println(secsSince1900);

    // NTP time in "echte" Zeit umwandeln:
    Serial.print("Unix Zeit = ");
    // Ausgabe der Unix time:
    Serial.println(epoch);

    // Stunde, Minute, Sekunde ausgeben:
    Serial.print("Die UTC Zeit ist "); // UTC entspricht Greenwich Meridian (GMT)
    Serial.print((epoch % 86400L) / 3600); // Stunde ausgeben (86400 sind die Sekunden pro Tag)
    Serial.print(':');
    if (((epoch % 3600) / 60) < 10) {
        // In den ersten 10 Minuten einer Stunde brauchen wir eine führende Null
        Serial.print('0');
    }
    Serial.print((epoch % 3600) / 60); // Minute ausgeben (3600 = Sekunden pro Stunde)
    Serial.print(':');
    if ((epoch % 60) < 10) {
        // In den ersten 10 Minuten einer Stunde brauchen wir eine führende Null
        Serial.print('0');
    }
    Serial.println(epoch % 60); // Sekunde ausgeben
#endif

    return epoch;
}

// Lokale Zeit mittels RTC (Real Time Clock) ermitteln:
String getLocaltime()
{
    char buffer[32];
    tm t;
    _rtc_localtime(time(NULL), &t, RTC_FULL_LEAP_YEAR_SUPPORT);
    strftime(buffer, 32, "%Y-%m-%d %k:%M:%S", &t);
    return String(buffer);
}

Für Interessierte, die mehr über das NTP (Network Time Protocol) erfahren möchten, eine Abbildung mit anschließenden Erläuterungen, die den Aufbau eines NTP-Pakets veranschaulichen:

Mit dem NTP-Protokoll können eingebettete Systeme ihre Echtzeituhr setzen

Die Header-Einträge eines NTP-Pakets gestalten sich oben wie folgt:

LI

Leap Indicator (2 bits)

Dieses Attribut zeigt an, ob die letzte Minute des aktuellen Tages eine Zusatzsekunde benötigt.

0: Keine Sekundenanpassung nötig

1: Letzte Minute soll 61 sec haben

2: Letzte Minute soll 59 sec haben

3: Uhr wird nicht synchronisiert

VN

NTP-Versionsnummer (3 Bits) (etwa Version 4).

Mode

NTP-Paketmodus (3 Bits)

0: Reserviert

1: Symmetrisch aktiv

2: Symmetrisch passiv

3: Client

4: Server

5: Broadcast

6: NTP-Kontrollnachricht

7: Für private Nutzung reserviert

Stratum

Stratum-Ebene der Zeitquelle (8 bits)

0: Unspezifiziert oder ungültig

1: Primärer Server

2–15: Sekundärer Server

16: Unsynchronisiert

17–255: Reserviert

Poll

Poll Interval (8-Bit Ganzzahl mit Vorzeichen), die in Sekunden definiert, was das maximale Zeitintervall zwischen aufeinander folgenden NTP-Nachrichten sein soll.

Precision

Präzision der Uhr (8-Bit Ganzzahl mit Vorzeichen)

Root Delay

Die Round-Trip-Verzögerung vom Server zur primären Zeitquelle. Es handelt sich um eine 32-Bit Gleitpunktzahl, die Sekunden festlegt. Der Dezimalpunkt befindet sich zwischen Bits 15 und 16. Sie ist nur für Server-Nachrichten relevant.

Root Dispersion

Der maximale Fehler aufgrund der Toleranz bezüglich der Uhr-Frequenz. Es handelt sich um eine 32-Bit Gleitpunktzahl, die Sekunden festlegt. Der Dezimalpunkt befindet sich zwischen Bits 15 und 16. Sie ist nur für Servernachrichten relevant

Reference Identifier

Bei Stratum-1-Servern beschreibt dieser Wert (ein ASCII-Wert mit 4 Bytes) die externen Referenzquellen. Für sekundäre Server beschreibt der Wert (4 Bytes) die IPv4-Adresse der Synchronisationsquelle, oder die ersten 32 Bit des MDA-Hashes (MDA = Message Digest Algorithm 5) der IPv6-Adresse des Synchronisationsservers.

Der Sensor

Um den BME688-Sensor über I2C anzusteuern, müssen wir Bibliotheken von Adafruit über den Bibliotheksmanager laden - der Code lässt sich einfach umstellen, um stattdessen SPI zu verwenden. Importieren muss man die Bibliotheken Adafruit BME680 und Adafruit Unified Sensor. Es kann natürlich auch die Bibliothek eines anderen Sensors aus der BME-Familie von Bosch sein, etwa die eines BME280.

Die Initialisierung des Sensors ist in setup() integriert. Hier die Vereinbarung des BME-Proxies:

Adafruit_BME680 bme; // Vereinbarung der Variablen bme

Und hier die eigentliche Initialisierung:

  // Verbindung mit Sensor BME680 etablieren
  if (!bme.begin()) {
    Serial.println(F("Konnte keinen Sensor finden. Bitte Schaltung überprüfen!"));
    while (1);
  }

  // Oversampling-Werte setzen und IIR-Filter initialisieren
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150); // 320*C für 150 ms
}

Ab geht die POST

Die Methode createJSONString() konstruiert aus Messdaten und Zeitstempel ein JSON-Objekt. Ich habe hier bewusst ein manuelles Erstellen gewählt, statt ArduinoJson zu verwenden, weil der Aufwand sehr übersichtlich bleibt:

// Hier wird ein String generiert, der ein JSON-Objekt enthält
String createJSONString(double temp, double humi, double pres, double resi, String date, String time) {
  String result = "{";
  const String up = "\"";
  const String delim = ",";
  const String colon = ":";

  result += up + "temperature" + up + colon + String(temp,2) + delim;
  result += up + "humidity"    + up + colon + String(humi,2) + delim;
  result += up + "pressure"    + up + colon + String(pres,2) + delim;
  result += up + "resistance"  + up + colon + String(resi,2) + delim;
  result += up + "date"        + up + colon + up + date + up + delim;
  result += up + "time"        + up + colon + up + time + up;
  result += "}";
  return result;
}

Wer einen Sensor besitzt, der einige dieser Messdaten nicht enthält, stutzt das JSON-Objekt entsprechend. In der Server-Datenbank wird für jedes nicht übergebene Attribut einfach ein null eingetragen.

Für das Versenden der Messdaten über HTTP-POST ist callAPIPost() verantwortlich, das anschließend auch die Antwort des Servers ausgibt, der im Erfolgsfall mit Status-Code 200 antwortet:

// Hier erfolgt die Vorbereitung und die eigentliche Durchführung des POST-Aufrufes / REST-PUSH 
void callAPIPost(double temperature, double humidity, double pressure, double resistance, const String& date, const String& time){
  Serial.println("Durchführung eines neuen REST API POST Aufrufs:");
  String contentType = "application/json"; // Wir übergeben ein JSON-Objekt

  // JSON Nutzlast (Body) kreieren
  String postData = createJSONString(temperature, humidity, pressure, resistance, date, time);
  Serial.println(postData); // ... und ausgeben

  // Per WiFi-Verbindung POST aufrufen und dabei "application/json" und das JSON-Objekt übergeben
  client.post("/measurements/api", contentType, postData);

  // Status und Body aus Antwort extrahieren
  int statusCode = client.responseStatusCode();
  String response = client.responseBody();

  // Ausgabe der Ergebnisse:
  Serial.print("Status code: ");
  Serial.println(statusCode);
  Serial.print("Antwort: ");
  Serial.println(response);
}

Aufrufe der vorgenannten Methoden finden in der loop()-Methode statt, außer natürlich die Initialisierungen beim Programmstart.

Läuft der Sketch, verbindet er sich über WiFi mit dem WLAN, misst kontinuierlich Daten vom BME688 und übermittelt sie und einen Zeitstempel als JSON-Objekt per POST an den Server

Fazit

Damit ist der Arduino-Sketch fertig, der den REST-Server aus Teil 1 mit neuen Messungen versorgt. Natürlich gibt es wie immer Erweiterungsmöglichkeiten:

  • So ließe sich ein SSD1306-OLED-Display hinzufügen, das die jeweiligen Messwerte ausgibt. Oder ein SD-Karten-basierter Datenlogger. Ein Beispiel für die zusätzliche Integration eines OLED-Displays mit IIC-Anschluss findet sich ebenfalls auf dem oben erwähnten GitHub Repository. Der Sensor und das I2C-Display sind per Daisy-Chain hintereinander geschaltet. Gegebenenfalls muss man die IIC-Adresse (default: 0x3C) und die Auflösung (default: 128x64) für die eigene Konfiguration ändern.

Das am IIC-Bus seriell angeschlossene SSD1306-Display (128 x 64) gibt die Daten der aktuellen Messung aus

Hier werden der Anschluss für 3.3V, GND, SDA, SCL vom Arduino auf ein Breadboard geführt, von wo sie IIC-Display und IIC-Sensor abgreifen können.

  • Denkbar ist das Nutzen anderer Klimasensoren wie BME280, BME580 oder sogar anderer Typen von Sensoren. Das erfordert Änderungen sowohl am Client- als auch am Server-Code.
  • Wer verschiedene Boards mit Sensoren besitzt, könnte dem Datenschema Attribute wie Board-Kennung und GPS-Daten mitgeben.
  • Es könnten alternative Boards wie Raspberry Pi Picos, ESP32-Boards zum Einsatz kommen. Sogar das direkte Anschließen eines BME688 an den Mac OS/Windows/Linux-Computer ist über ein GPIO-Erweiterungsboard möglich [3].
  • Eine App fürs Handy oder Tablet könnte den aktuellen Messverlauf grafisch visualisieren.

Und das ist immer noch nicht das Ende der Fahnenstange. Die Möglichkeiten sind fast unendlich. Client- und Server-Anwendungen des Beispiels sollten das Vorgehen dabei gut veranschaulichen und zu eigenen Experimenten anreizen. Die Implementierungen für Client und Server lassen sich entsprechend anpassen.

Ich hoffe jedenfalls, der hier vorgestellte Showcase bietet viel Nutzen und macht Spaß.


URL dieses Artikels:
https://www.heise.de/-9179967

Links in diesem Artikel:
[1] https://www.heise.de/blog/Gib-mir-den-REST-Teil-1-Der-REST-Server-9179764.html
[2] https://github.com/ms1963/RESTCommunication
[3] https://www.heise.de/blog/Fernsteuerung-per-Computer-GPIO-Breakout-Boards-als-Schweizer-Taschenmesser-7091889.html
[4] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 05. Juli 2023 um 15:40

Java: Oracles GraalVM ist ab sofort für alle kostenlos

Von heise online

(Bild: Shutterstock)

Das ehemals kostenpflichtige GraalVM Enterprise ist jetzt als Oracle GraalVM frei verfügbar. Die Versionsnummerierung wurde zudem dem OpenJDK angepasst.

GraalVM ist eine in Java implementierte JVM (Java Virtual Machine) und ein JDK (Java Developement Kit) basierend auf der Hotspot-VM und dem OpenJDK. Es unterstützt mit GraalVM Native Image unter anderem die AOT-Kompilierung (Ahead of Time) von Java Anwendungen für schnellere Startzeiten und geringeren Speicherverbrauch zur Laufzeit. Initial bei Sun gestartet wird es nun bei den Oracle Labs parallel zu dem klassischen Java OpenJDK entwickelt und war bisher sowohl in einer Open Source lizenzierten Community Edition als auch einer kommerziellen Enterprise Edition verfügbar.

Die Besonderheiten zum normalen Java JDK sind:

  • ein JIT (Just in Time) Compiler für Java in Java implementiert
  • GraalVM Native Image für die AOT (Ahead of Time) Kompilierung von Java Anwendungen
  • Truffle Language Implementierung und das GraalVM SDK für die Unterstützung zusätzlicher Programmiersprachen auf der VM
  • Runtimes für LLVM (C/C++, Fortran können zu Low Level Virtual Machine Bitcode übersetzt werden) und JavaScript

Was bisher geschah

Ende 2022 hat Oracle die GraalVM Community Edition an das OpenJDK-Projekt übergeben [1] und damit die Basis des Projekts als Open Source bereitgestellt. Dabei wurde angekündigt, zukünftig die Versionen und Nummerierungen an die Release-Zyklen des OpenJDK anzugleichen. Die erste produktionsreife Version war GraalVM 19.0 im Mai 2019 [2]. Mit GraalVM 22.3.2 kam im April 2023 das bisher letzte Release nach dem alten Nummerierungsschema.

Nun sind Oracle GraalVM für das JDK 17 und Oracle GraalVM für das JDK 20 erschienen [3]. Diese früher als kommerzielle Oracle GraalVM Enterprise bekannten Versionen stehen ab sofort kostenfrei unter der GraalVM Free Terms and Conditions (GFTC) Lizenz zur Verfügung. Diese Lizenz erlaubt die kostenlose Nutzung für alle Benutzer, auch für den Produktionseinsatz. Die Weiterverbreitung ist erlaubt, wenn sie nicht gegen eine Gebühr erfolgt. Entwickler und Organisationen können Oracle GraalVM jetzt einfach herunterladen, verwenden, weitergeben und weiterverteilen, ohne dass sie eine Lizenzvereinbarung durchklicken müssen. Oracle wird weiterhin die GPL-lizenzierten Versionen der GraalVM Community Edition zu den gleichen Bedingungen wie die Oracle-Builds des OpenJDK anbieten.

Etwas unklar ist im Moment die Frage, ob man die eigene Software, die als GraalVM Native Image gebaut wurde, nach GFTC-Lizenz verkaufen darf. Unser Leser Michael Paus hat uns auf eine Diskussion im GraalVM Slack [4] aufmerksam gemacht (um diesen Beitrag lesen zu können, muss man sich zuvor als Benutzer registrieren [5]). Nach dem aktuellen Stand der Diskussion darf man als GraalVM Native Image gebaute Software in Produktion nur kostenfrei für die interne Nutzung oder als Open Source betreiben. Verlangt man eine Gebühr für die eigene Software, muss man auf eine kommerzielle Lizenz von GraalVM ausweichen. Die Kosten dafür richten sich entweder nach den Prozessorkernen, auf denen das Native Image laufen wird oder es wird ein nicht geringer Pauschalbetrag fällig. Auskünfte dazu holt man sich am besten direkt beim Sales & Tech Team bei Oracle ein.

Parallelen zum OpenJDK

Kurzer Blick auf das klassische Java OpenJDK: Im September 2021 hatte Oracle angekündigt, dass das Oracle JDK (Oracles Variante des OpenJDK) wieder kostenfrei zur Verfügung steht (unter der Oracle No-Fee Terms and Conditions Lizenz - NFTC). Zuvor hatte Oracle 2018 mit dem JDK 8 und 11 eine kommerzielle Lizenz für die produktive Nutzung des Oracle JDK eingeführt.

Alternativ gab es zwar noch das binär-kompatible Oracle OpenJDK kostenfrei, welches aber immer nur maximal ein halbes Jahr mit Updates und Patches versorgt wurde und somit die Entwickler zu halbjährlichen JDK Versionsupdates gezwungen hätte. Seit dieser Zeit sind viele andere auf dem OpenJDK basierende Distributionen von Amazon, IBM, SAP, Microsoft usw. herausgekommen beziehungsweise haben an Bedeutung gewonnen.

Die bekannteste Variante ist das AdoptOpenJDK (mittlerweile Temurin vom Eclipse Projekt Adoptium [6]), welches durch Oracles Lizenz-Wirrwar zum meistverwendeten JDK wurde. Oracle hat das erkannt und durch die erneute kostenfreie Weitergabe des Oracle JDK versucht, Marktanteile zurückzugewinnen. Diesen Ansatz weiten sie nun auch auf Oracle GraalVM mit der GraalVM Free Terms and Conditions (GFTC)-Lizenz aus.

Analog dem OpenJDK wird es nun ebenfalls Long Term Support Releases (aktuell GraalVM für JDK 17) geben, die bis zu einem vollen Jahr nach der Veröffentlichung des nachfolgenden LTS-Release (GraalVM für JDK 21) kostenlos mit Updates versorgt werden. Releases, die nicht als LTS-Releases gekennzeichnet sind (wie GraalVM für JDK 20), werden so lange mit Aktualisierungen versorgt, bis sie durch das nächste Release abgelöst werden. Entwickler können somit jetzt auch bei GraalVM alle sechs Monate auf die neueste JDK-Version aktualisieren und erhalten so sofort Zugang zu den neuesten Java-Funktionen. Alternativ haben Sie die Möglichkeit, zwischen den LTS-Versionen zu wechseln.

Die neuen Oracle GraalVM-Releases lassen sich dank neuer stabiler Download-URLs jetzt leichter in CI/CD-Build-Pipelines einbinden. Die Download-Artefakte enthalten zudem das Native-Image-Dienstprogramm. Somit ist alles in einem einzigen Paket unter derselben Lizenz verfügbar, was für die Entwicklung mit der GraalVM benötigt wird. Für containerisierte Anwendungen oder Container-basierte Builds werden zudem bald neue GraalVM Container-Images auf der Oracle Container Registry verfügbar sein.

Einordnung

Das GraalVM Projekt hat in den vergangenen Jahren eine Menge Aufmerksamkeit erhalten. Das Ziel ist, Javas Rückstand auf moderne Programmiersprachen wie Go in Bezug auf schnelle Startzeiten und effizientes Speicherverhalten zur Laufzeit zu verkleinern. Java ist zwar weiterhin als stabile Laufzeitumgebung für serverseitige Anwendungen vertreten, verliert aber insbesondere beim Umzug in die Cloud Marktanteile an Go & Co. Mit der GraalVM hat man nun auf der Java Plattform die Wahl und kann mit den bestehenden Programmierkenntnissen beide Welten unterstützen. Die Angleichung der Release-Zyklen und der Versionierung an das OpenJDK lassen uns die neuesten Features sowohl im "normalen" Java als auch bei der GraalVM nutzen.

Die Änderungen an den neuen, im Juni 2023 erschienenen GraalVM-Versionen hat Alina Yurenko in ihrem Blog-Post [7] zusammengefasst.

Die neuen Oracle GraalVM Versionen können von der Java-Download-Seite [8] bezogen werden. Weitere Informationen [9] finden sich in den Installationsanleitungen, der Dokumentation und den Versionshinweisen. In der Oracle Cloud Infrastruktur kann Oracle GraalVM übrigens kostenfrei genutzt werden.

Update

Nach Hinweis eines Lesers wurde der Beitrag um einen Absatz ergänzt, der sich den Unklarheiten bezüglich der Bedingungen zum Verkauf eigener Software widmet, die mit GraalVM Native Image gebaut wurden.


URL dieses Artikels:
https://www.heise.de/-9199872

Links in diesem Artikel:
[1] https://www.heise.de/news/Virtuelle-Maschine-Oracle-uebergibt-GraalVM-Community-Edition-an-OpenJDK-7320608.html
[2] https://www.heise.de/news/GraalVM-19-das-erste-offiziell-produktionsreife-Release-4420777.html
[3] https://blogs.oracle.com/cloud-infrastructure/post/graalvm-free-license
[4] https://t.co/Ga1lgeLr91
[5] https://t.co/JFAWTJ9niQ
[6] https://www.heise.de/news/AdoptOpenJDK-landet-bei-der-Eclipse-Foundation-4789835.html
[7] https://medium.com/graalvm/a-new-graalvm-release-and-new-free-license-4aab483692f5
[8] https://www.oracle.com/java/technologies/downloads/
[9] https://docs.oracle.com/en/graalvm/jdk/20/
[10] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 30. Juni 2023 um 12:33

Logging Facades für Java

Von heise online

(Bild: Black Jack/Shutterstock.com)

Logging ein wichtiger Teil der Fehleranalyse. Allerdings ist das Zusammenführen unterschiedlicher Logging Libs in Java-Anwendungen immer eine Herausforderung.

Nachdem ich im ersten Post zum Thema Java Logging [1] auf Best Practices und Pitfalls eingegangen bin, möchte ich nun einmal auf die Nutzung von Logging in einem großen Projekt eingehen. In diesem Bereich kommt es oft zu Problemen zwischen verschiedenen Logging Frameworks und eine Zusammenführung des gesamten Anwendung-Logging kann sich mitunter schwer gestalten.

Um die Problematik besser zu verstehen, fange ich mit einem ganz einfachen Beispiel, quasi dem Hello World im Logging, an. Der folgende Code zeigt eine minimale Java-Anwendung, welche einfach eine Nachricht loggt:

public class HelloLogging {

    private static final Logger LOG = Logger.getLogger("HelloLogging");

    public static void main(final String[] args) {
        LOG.info("Hello World");
    }
}

Bereits in dieser trivialen Anwendung kann das Logging durch die Features des Logging Frameworks, im Beispiel etwa java.util.Logging (JUL), konfiguriert und in einer Datei oder der Konsole (Shell) ausgegeben werden. Das folgende Diagramm zeigt den Aufbau und die Konfiguration des Logging in einem schematischen Aufbau.

Ein realistisches Szenario

Während der gegebene Aufbau für ein kleines Projekt gut funktioniert, wird es manchmal schon problematisch, sobald die ersten Abhängigkeiten hinzukommen. Stellen wir uns einmal vor, dass wir zwei Abhängigkeiten für unsere Anwendung benötigen: eine Library, um den Zugriff zu einer Datenbank zu gewährleisten und eine weitere Abhängigkeit zu einer Security Library, um unsere Anwendung sicher vor Angriffen zu machen. Da die Entwickler dieser Bibliotheken auch Information über dessen Zustand, Nutzung und Laufzeitfehler ausgeben wollen, nutzen diese ebenfalls Logging. Allerdings wird bei diesen Bibliotheken nicht java.util.Logging, sondern es werden andere Logging Libraries genutzt. Wie man im folgenden Diagramm sehen kann, nehmen wir an, dass Log4J2 [2] und Logback [3] im Einsatz sind.

Nun haben wir das Problem, dass das Logging unserer Anwendung über drei verschiedene Logging-Frameworks geleitet wird. Zwar bieten Log4J und Logback auch genug Möglichkeiten der Konfiguration, aber da die Logging Frameworks sich nicht gegenseitig synchronisieren, wäre es eine ganz dumme Idee, alle Frameworks in die gleiche Datei schreiben zu lassen. Hier kann es passieren, dass mehrere der Frameworks in die gleiche Zeile schreiben und es somit zu einem unleserlichen Haufen zufällig aneinandergereihter Textbausteine oder sogar zu Deadlocks kommen kann. Eine andere Idee ist es, dass jedes Framework in eine eigene Datei loggt, wie es im folgenden Diagramm angedeutet ist.

Dieser Aufbau führt dazu, dass die Loggings völlig unabhängig voneinander agieren und sich nicht in die Quere kommen können. Hierdurch hat man zwar ein sauberes Logging, das aber auf mehrere Dateien verteilt ist, die man manuell oder mithilfe von Tools synchronisieren muss. Dazu kommt, dass man immer alle vorhandenen Loggingsysteme konfigurieren muss, wenn man beispielsweise einmal ein höheres Logging-Level zur Analyse der Anwendung aktivieren möchte. Erschwerend kommt hinzu, dass man in einem echten Projekt mehr als nur zwei Abhängigkeiten hat uns es somit zu noch deutlich mehr Logging-Frameworks kommen kann, die im Einsatz sind.

Globales Logging durch den Einsatz einer Facade

Logging Facades schaffen hier Abhilfe. Durch eine Facade kann man den Code von einer konkreten Implementierung trennen. Die Simple Logging Facade for Java [4] (SLF4J) hat sich hier ganz klar als Standard durchgesetzt. SLF4J bietet eine Logging-API, die als einzelne Abhängigkeit ohne transitiven Abhängigkeiten daher kommt und problemlos in so ziemlich jedes System eingebunden werden kann. Die API kann in diesem Fall genutzt werden, um konkrete Log-Aufrufe im Code zu genieren. Der folgende Code zeigt ein „Hello World“ Logging Beispiel:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloLogging {

    private static final Logger logger = 
      LoggerFactory.getLogger(HelloLogging.class);

    public static void main(String[] args) {
        logger.info("Hello World!");
    }
}

Betrachtet man rein diesen Code kann man sich fragen, welche Vorteile SLF4J gegenüber dem klassischen Java-Logging bringen soll. Einer der wichtigsten Punkte ist, dass es sich bei org.slf4j.Logger um ein Interface handelt. Das Modul slf4j-api, das die SLF4J-Api und somit das genannte Interface enthält, liefert keine Implementierung des Interfaces. Das gesamte Modul definiert lediglich die öffentliche API api von SLF4J, die Logging Facade.

Um sie zu nutzen, müssen wir eine Implementierung bereitstellen. Hierfür muss ein sogenanntes Binding als Abhängigkeit hinzugefügt werden, das eine Implementierung der Logging Facade bereitstellt. In der Regel leitet ein solches Binding die Logging-Events an ein konkretes Logging-Framework weiter. Möchte man beispielsweise Apache Commons Logging als konkrete Logging-Implementierung nutzen, muss man nur das slf4j-jcl-VERSION.jar Modul zum Classpath hinzufügen. Solche Bindings werden nicht zur Compiletime benötigt und können daher in Maven per Runtime-Scope bzw. in Gradle als „RuntimeOnly“-Abhängigkeit angegeben werden. Da SLF4J intern das Java-SPI nutzt, muss keinerlei Code angepasst werden, um die konkrete Logging-Implementierung zu verwenden. Dieses Feature können wir nun für unsere Beispielanwendung nutzen:

Nutzung von SLF4J und Log4J2 als Implementierung

Im Diagramm wird Log4J2 als Logging-Implementierung genutzt, und durch das Hinzufügen eines passenden Bindings werden alle Log-Nachrichten, die über den org.slf4j.Logger-Logger erstellt werden, automatisch an Log4J2 weitergereicht. Da in diesem Beispiel unsere „Database lib“ Abhängigkeit offenbar auch Log4J2 nutzt, werden so direkt die Nachrichten von verschiedenen internen und externen Modulen über Log4J2 abgehandelt. Neben den Bindings zu speziellen Logging Implementierung bietet SLF4J auch noch die Library slf4j-simple welche eine minimale Implementierung von SLF4J bietet und Nachrichten auf der Konsole (System.error) ausgibt.

Allerdings gibt es im Beispiel auch noch ein Problem: Die genutzte „Security lib“ benutzt Logback als Logger und dessen Nachrichten landen daher weiterhin in einer anderen Ausgabe. Für solche Fälle können sogenannte Adapter für SLF4J genutzt werden. Diese ermöglichen, dass Log-Nachrichten, die direkt zu einer Logging-API geschickt werden, an SLF4J weitergeleitet werden. Hierbei gibt es je nach Logging Framework völlig unterschiedliche Implementierungsansätze für solche Adapter. Während SLF4J einige solcher Adapter anbietet, werden ie auch teils von Logging-Frameworks direkt geliefert. Für Log4J2 muss beispielsweise folgende Abhängigkeit hinzugefügt werden, wenn man Nachrichten von Log4J2 an SLF4J weiterleiten möchte:

<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>

Durch das Hinzufügen dieser Abhängigkeit, die man am besten nur zur Runtime zum Classpath hinzufügt, entsteht ein Verlauf des Logging wie in der folgenden Grafik :

SLF4J und Log4J2

SLF4J bietet für verschiedene Logging-Libraries eine gute Übersicht bezüglich der Integration durch Bindings und Adapter auf ihrer Webseite [5].

Wenn wir uns basierend auf den Erkenntnissen nun unsere Beispielanwendung anschauen, kann durch das Hinzufügen eines Adapters für Logback unser Ziel erreicht werden. Wie im folgenden Diagramm gezeigt, werden alle Log-Nachrichten des gesamten Systems über Log4J2 geleitet und wir haben somit den Vorteil, dass wir nur eine zentrale Stelle dokumentieren müssen.

Korrekte Nutzung einer Logging Facade


URL dieses Artikels:
https://www.heise.de/-7355974

Links in diesem Artikel:
[1] https://www.heise.de/blog/Best-Practices-und-Anti-Pattern-beim-Logging-in-Java-und-anderen-Sprachen-7336005.html
[2] https://logging.apache.org/log4j/2.x/
[3] https://github.com/qos-ch/logback
[4] https://www.slf4j.org
[5] https://www.slf4j.org/legacy.html
[6] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 22. Juni 2023 um 17:13

Apple Vision Pro: Einsatz in geschäftlichen und industriellen Anwendungen

Von heise online

Kult oder Kultur? Apple's Vision Pro Konzept.

(Bild: apple.com)

Der Blog möchte nicht auf einen fahrenden Zug aufspringen, sondern erläutern, wie sich das Konzept der Vision Pro in industriellen Umgebungen nutzen lässt.

Auf der diesjährigen WWDC 2023 (World Wide Developer Conference) von Apple hat Tim Cook die seit Jahren "sagenumwobene" Vision Pro Brille vorgestellt. Auf YouTube finden sich hierzu viele Videos, weshalb sich dieser kurze Beitrag eine Wiederholung der dortigen Erkenntnisse spart.

Eines vorweg: es geht hier nicht primär um Apple und sein neuestes Produkt, sondern um die Betrachtung des zugrundeliegenden Konzepts und seiner möglichen Einsatzgebiete.

Aber etwas Kontext muss trotzdem sein: Jedenfalls soll die Vision Pro dank vieler Sensoren und Kameras sowie einer Auflösung von 4K für die beiden Bildschirme ein Augmented Reality der Zukunft bieten. Apple nennt dies bewusst Spatial Computing (räumliche Verarbeitung) statt auf überfrachtete Terminologie wie AR (Augmented Reality) oder MR (Mixed Reality) zurückzugreifen. So lassen sich im realen Raum virtuelle Hintergründe oder Umgebungen integrieren, in deren Kontext Anwender ihre Arbeits- oder Entertainment-Umgebung gestalten können. Der Grad an Virtualität ist also nach eigenem Gusto steuerbar.

Mit einem veranschlagten Preis von 3500 US-Dollar gehört das neue Gadget nicht gerade zu den Schnäppchen. Was aber viele übersehen: Apple sieht sich hier nicht im Wettbewerb mit Giganten wie Meta und deren Oculus-Produktfamilie, sondern adressiert eher das Marktsegment, das auch die 3200-US-Dollar teure Hololens von Microsoft abdeckt. Und das sind eher Businessanwender und vielleicht ein paar Technologie-Junkies mit großem Sparstrumpf. Ein Spielzeug für Gamer ist die Brille also nicht. Daher ist zu erwarten, dass Apps für die Vision Pro ebenfalls dieses Marktsegment adressieren und sich nicht unbedingt im unteren Preissegment tummeln.

Brille für industrielle Anwendungen

Nach Ansicht des Autors könnte das Produkt gerade für geschäftliche und industrielle Umgebungen interessant sein. So erschließt das Konzept folgende Domänen und Anwendungsfälle:

  • Wartungsszenarien: Hier nutzen Wartungsspezialisten die Brille, um sich in der Fabrik oder Anlage interne Details zu gerade betrachteten Komponenten in der Brille anzeigen zu lassen oder generell Hilfe für die Wartung zu erhalten.
  • Medizinische Geräte: Über Wartungsszenarien für Modalitäten oder für Labordiagnostik hinaus könnten Ärzte die Brille für die Befundung verwenden, etwa in Zusammenhang mit einem Bildarchivierungssystem.
  • Navigations- und Logistikanwendungen: Für mobile Wartungsexperten und Lagermitarbeiter wäre der Einsatz der Vision Pro denkbar, um sich an die richtigen Orte leiten zu lassen.
  • Bedienen und Beobachten: In der Industrieautomatisierung wäre ein Konzept überlegenswert, das ein Bedienen oder Beobachten einzelner SPSen (Speicher Programmierbare Steuerungen), SCADA-Systeme und anderer Systeme ermöglicht.
  • Kreativität: Eine Vision Pro ließe sich für den Entwurf neuer Schaltungen, Architekturen und künstlicher Artefakte einsetzen, an denen Anwender weitgehend ohne Ablenkung virtuell arbeiten könnten.
  • Militär: Dass sich die Vision Pro für militärische Anwendung zweckentfremden ließe, steht außer Frage, etwa für die Anzeige wichtiger Informationen auf dem Feld.

Gerade die Mobilität der Brille erweist sich in diesen Szenarien als Vorteil, mal abgesehen von dem signifikanten Nachteil, dass der separat erhältliche Hochleistung-Akku gerade mal zwei Stunden durchhält. Natürlich stellt all das nur die Spitze des Eisbergs dar. Da noch niemand die Vision Pro in der Praxis prüfen konnte, gibt es viel Raum für reine Spekulation. Interessierte Entwicklungsschmieden und User sollten sich trotzdem schon jetzt ein paar Gedanken über mögliche Anwendungen machen.

All das führt natürlich unweigerlich zu Überlegungen hinsichtlich von Software- und Systemarchitektur der entsprechenden Systeme und Anwendungen. Auch die Kombination mit KI in einer Spatial-Computing-Anwendung könnte sinnvoll sein, etwa für die visuelle Einschätzung möglicher Fehlerursachen bei der Systemwartung.

Die Apple Vision Pro [1] ließe sich ergo als wichtiger Bestandteil neuer oder geänderter Anwendungsfelder etablieren. Ob die Konkurrenz dem etwas entgegensetzen will beziehungsweise kann, bleibt abzuwarten. Zumindest sollte das Konzept Entwickler und Anwender anregen, wie sie diese Art von Produkt sinnvoll und produktiv in ihren Domänen oder für sich selbst nutzen können. Die Zukunft beginnt jetzt.


URL dieses Artikels:
https://www.heise.de/-9181574

Links in diesem Artikel:
[1] https://www.heise.de/news/Apples-Vision-Pro-Apples-Mixed-Reality-Headset-enthuellt-9168785.html
[2] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 12. Juni 2023 um 14:15

Gib mir den REST – Teil 1: Der REST-Server

Von heise online

(Bild: Bogdan Vija / Shutterstock.com)

Wie kommuniziert ein Arduino-Board serverseitig mit einer REST API, um Sensor-Messungen über ein objektrelationales Mapping zu speichern?

Arduino-Boards, die über eine optionale Echtzeituhr (RTC = Real Time Clock) und ein WiFi-Modul verfügen, lassen sich ins Internet der Dinge integrieren, etwa über die Arduino Cloud oder AWS. Wer lieber On-premises agieren möchte, kann anders vorgehen und Server beziehungsweise Clients im heimischen Netz zur Verfügung stellen. Das bringt den Vorteil mit sich, immer die Kontrolle über die Bereitstellung (Deployment) zu behalten. Wie Entwicklerinnen und Entwickler dabei vorgehen können, zeigen dieser und der nachfolgende Artikel. Während zunächst die Server-Anwendung zur Sprache kommt, dreht sich der zweite Teil um die eingebetteten Clients.

Gleich vorweg: alle Implementierungsdateien liegen auf GitHub [1] parat. Eine gute Gelegenheit, um sich mühselige Handarbeit zu ersparen.

Grobe Systemarchitektur

Im Beispielsszenario kommen ein Arduino Board mit C++-Sketch und ein Server mit Java und Spring Boot 3 zum Einsatz.

Die folgende Abbildung zeigt die Systemarchitektur:

Ein Arduino-Client kommuniziert mit der REST-API auf dem Server

Auf der linken Seite der Grafik ist das Arduino-Board, konkret ein Arduino Giga R1 WiFi, zu sehen. Verwendbar sind aber grundsätzlich alle Arduino-Boards oder Arduino-unterstützte Boards wie etwa ein ESP32. Am Arduino ist ein BME688-Sensor von Adafruit über I2C oder SPI angeschlossen. Der Arduino-Sketch macht periodisch Messungen von Temperatur, Feuchtigkeit, Luftdruck und Gaswiderstand, und verschickt das Ergebnis zusammen mit dem von der Echtzeituhr ausgelesenen Zeitstempel über einen POST-Aufruf an den Server: <hostname>:8080/measurement/api. <hostname> kann dabei die IP-Adresse oder der DNS- beziehungsweise Server-Name sein.

Serverseitig (rechte Seite in der Abbildung) fungiert eine in Java geschriebene Spring-Boot-3-REST-Anwendung als Kommunikationspartner für das Arduino-Board. Die zugehörige Datenbank läuft auf PostgreSQL, das die Anwendung als Docker-Container bereitstellt. So ist sichergestellt, dass Entwicklerinnen und Entwickler PostgreSQL auf dem eigenen Computer nicht extra installieren müssen.

Zur Laufzeit sendet das Arduino-Board POST-Nachrichten an den Server. Der dazugehörige REST-Endpunkt sorgt dann dafür, dass die Messung in die Datenbank übernommen wird.

Der Server

Selbstverständlich lassen sich auch andere Datenbankmanagementsysteme nutzen, etwa mysql (maria). In diesem Fall müssten nur die Konfigurationsdateien application.yml sowie docker-compose.yml angepasst werden. Und in der Konfigurationsdatei pom.xml – das Projekt nutzt Maven für den Build-Prozess – sind entsprechend die PostgreSQL-Referenzenen durch die für die alternative Datenbank notwendigen Abhängigkeiten (<dependencies>) zu ersetzen. Wie aus folgender Abhängigkeits-Festlegung ersichtlich, gilt das nur für die zweite Abhängigkeit in Bezug auf PostgreSQL – in diesem Fall den pgJDBC-Treiber. Der soll übrigens nur zur Laufzeit aktiv sein, deshalb ist der benötigte Scope in der pom.xml-Datei mit runtime festgelegt. Alle anderen Abhängigkeiten beziehen sich auf Spring Boot, im Detail auf die Nutzung von Spring Web, Spring Data JPA (Java Persistence API) und Spring Test:

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

Als Adapter nutzt die Server-Anwendung einen über die URL [2] bereitstehenden JDBC-Treiber.

Für den Fall, dass Entwickler und Entwicklerinnen bereits eine lokale Instanz von postgreSQL einsetzen, ist in der Konfiguration des Docker-Containers ein Port-Mapping definiert. Dieses verbindet den Server-Port 5332 mit dem Container-Port 5432 und verhindert somit Konflikte mit lokalen postgreSQL-Installationen, die auf Port 5432 lauschen.

Sobald der Arduino-Client einen POST-Aufruf mit einer Messung auf die Reise schickt, nimmt die Server-Schnittstelle die Messung als JSON-Body im jeweiligen REST-POST-Endpunkt entgegen und speichert die Messdaten in der postgreSQL-Datenbank measurement.

Die REST-Anwendung nutzt Port 8080, was sich in der Konfigurationsdatei application.yml bequem ändern lässt.

server:
  port: 8080

#turn off the web server
spring:
  datasource:
    url: jdbc:postgresql://localhost:5332/measurement
    username: michael
    password: michael
  jpa:
    hibernate:
      ddl-auto: create-drop
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect
        format_sql: true
    show-sql: true
  main:
    web-application-type: servlet
Inbetriebnahme

Wer einfach loslegen will, startet nach Download der Quellen zunächst das Docker-Image. Dazu ist es erforderlich, auf dem eigenen Server beziehungsweise Desktop Docker zu installieren. Mittels der -> URL [3] bedeutet das zunächst, die entsprechende Docker-Implementierung für Linux, Windows oder macOS herunterzuladen und zu starten. In der Werkzeugleiste des Betriebssystems erscheint danach das für Docker typische Icon, ein Container-Frachtschiff.

Im nächsten Schritt sollten Entwickler und Entwicklerinnen die Konfiguration docker-compose.yml auf ihre Bedürfnisse anpassen:

services:
  db:
    container_name: postgres
    image: postgres
    environment:
      POSTGRES_USER: michael
      POSTGRES_PASSWORD: michael
      PGDATA: /data/postgres
    volumes:
      - db:/data/postgres
    ports:
      - "5332:5432"
    networks:
      - db
    restart: unless-stopped
networks:
  db:
    driver: bridge

volumes:
  db:

Am Anfang der Konfiguration sind die bereitgestellten Dienste spezifiziert. Als Basis soll der Container das auf Docker Hub bereitgestellte Postgres-Image verwenden.

Im Bereich environment erfolgt die Festlegung den Anwendernamens und des zugehörigen Passworts sowie des Ordners im Container, der die PostgreSQL-Dateien enthalten soll. Das interne Netzwerk heißt db und ist über eine Bridge erreichbar. Stoppt der Container, löscht er die Datenbanktabelle.

Wer ein anderes DBMS nutzt, muss diese YAML-Datei entsprechend anpassen.

Im Ordner, in dem die YAML-Datei liegt, erfolgt nun der Start des Containers über

%docker compose up -d

Nach Eingabe von

%docker container ls

in der Kommandozeile müsste der Container auftauchen:

CONTAINER ID   IMAGE      COMMAND                  CREATED       STATUS       PORTS                    NAMES​
d0cc2733c93a   postgres   "docker-entrypoint.s…"   4 hours ago   Up 4 hours   0.0.0.0:5332->5432/tcp   postgres​

Damit ist es allerdings nicht getan, denn es fehlt noch die Datenbank für die Messungen.

Zunächst öffnen wir dazu eine Shell im Container für den interaktiven Zugriff:

docker exec -it postgres bash

In der Container-Session ist im Falle von postgreSQL das Kommando:

psql - U michael

notwendig, wobei U für den Nutzer steht. Ohne Änderungen ist im Beispiel michael als Benutzername und Passwort für postgreSQL voreingestellt.

Über psql lassen sich mit \l die existierenden Datenbanken abrufen.

Hier erscheint in etwa die folgende Ausgabe:

Name     |  Owner  | Encoding |  Collate   |   Ctype    | ICU Locale | Locale Provider |  Access privileges  ​
-------------+---------+----------+------------+------------+------------+-----------------+---------------------​
libc            | ​
 michael     | michael | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            | ​
 postgres    | michael | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            | ​
 template0   | michael | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            | =c/michael         +​
             |         |          |            |            |            |                 | michael=CTc/michael​
 template1   | michael | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            | =c/michael         +​
             |         |          |            |            |            |                 | michael=CTc/michael
(4 rows)

Um eine neue Datenbank zu erzeugen, geben wir

CREATE DATABASE measurement;

ein.

Achtung: Der Strichpunkt ist unbedingt erforderlich. Mit \c measurement verbinden wir uns mit der Datenbank und können danach mit \dt die vorhandenen Tabellen beziehungsweise Datenbankschemas analysieren. Noch ist dort nichts zu sehen, weil für das Datenbankschema die Spring-Boot-3-Anwendung sorgt. Spring Boot kreiert zu diesem Zweck selbständig folgendes SQL-DDL-Kommando:

    create table measurement (​
       id integer not null,​
        date date,​
        humidity float(53),​
        pressure float(53),​
        resistance float(53),​
        temperature float(53),​
        time time,​
        primary key (id)​
    )​

Wer eine professionelle IDE wie IntelliJ IDEA Ultimate nutzt, kann viele der beschriebenen und kommenden Schritte bequem über die IDE anstoßen.

Nun müssen wir noch die Java-basierte Spring-Boot-3-Anwendung starten (mittels Main.class), wobei wir eine ähnliche Ausgabe wie die folgende erhalten sollten – nur die letzten zwei Zeilen sind hier abgebildet.

…. noch viel mehr ….

2023-06-04T15:18:01.952+02:00 INFO 51585 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''

2023-06-04T15:18:01.959+02:00 INFO 51585 --- [ main] de.stal.Main : Started Main in 3.172 seconds (process running for 3.807)

Es ist aus der Konsolenausgabe ersichtlich, dass Spring Boot für Webanwendungen automatisch den eingebetteten Web-Server Tomcat startet. Alternativ könnten wir auch Jetty nutzen, was folgende Konfigurationsänderung im pom.xml von Maven erfordert:

<dependency>​
    <groupId>org.springframework.boot</groupId>​
    <artifactId>spring-boot-starter-web</artifactId>​
    <exclusions>​
        <exclusion>​
            <groupId>org.springframework.boot</groupId>​
            <artifactId>spring-boot-starter-tomcat</artifactId>​
        </exclusion>​
    </exclusions>​
</dependency>​
<dependency>​
    <groupId>org.springframework.boot</groupId>​
    <artifactId>spring-boot-starter-jetty</artifactId>​
</dependency><dependency>​
    <groupId>org.springframework.boot</groupId>​
    <artifactId>spring-boot-starter-web</artifactId>​
    <exclusions>​
        <exclusion>​
            <groupId>org.springframework.boot</groupId>​
            <artifactId>spring-boot-starter-tomcat</artifactId>​
        </exclusion>​
    </exclusions>​
</dependency>​
<dependency>​
    <groupId>org.springframework.boot</groupId>​
    <artifactId>spring-boot-starter-jetty</artifactId>​
</dependency>​

In der Ausgabe befindet sich des Weiteren eine Warnung über Views, die wir in diesem Fall aber getrost ignorieren können.

Im Falle von gradle als Build-Tool wäre es stattdessen:

configurations {​
    compile.exclude module: "spring-boot-starter-tomcat"​
}​

dependencies {​
    compile("org.springframework.boot:spring-boot-starter-web:2.0.0.BUILD-SNAPSHOT")​
}

Das aber nur am Rande, weil das Beispielsprojekt wie schon erwähnt Maven einsetzt.

Immer wenn der Postman klingelt

Möchte man den Server auch ohne Arduino-Client testen, leistet die Anwendung Postman [4] hierfür gute Dienste. Sie ermöglicht das Aufrufen von APIs und benutzt curl als Basis dafür.

Mit postman lassen sich bequem REST-APIs testen

Das implementierte REST-Beispiel unterstützt folgende Aufrufe von REST-Endpunkten, um CRUD-Funktionalität (CRUD = Create Read Update Delete) bereitzustellen.

  • POST-Aufrufe dienen zum Anlegen neuer Messungen über hostname:port/measurements/api, wobei im Body ein JSON-Objekt mit den Messergebnissen enthalten sein muss.
  • GET-Aufrufe wie hostname:port/measurements/api brauchen keinen Body im HTTP-Paket (none). Der Endpunkt liefert die Liste aller gespeicherten Messungen zurück. Das gilt auch für das Auslesen von individuellen Einträgen über hostname:port/measurements/api/42. In diesem Fall beziehen wir uns auf die Messung mit der Id 42.
  • Der PUT-Aufruf wie etwa hostname:port/measurements/api/1 benötigt ein JSON-Objekt als Body, das die Werte des zum Datenbankeintrag gehörigen Primärschlüssels 1 aktualisiert.
  • Ein DELETE-Aufruf wie zum Beispiel hostname:port/measurements/api/2 löscht den Eintrag mit dem Primärschlüssel 2 aus der Datenbank. Ebenso wie bei GET ist kein Body (none) vonnöten.

Ein Beispiel für ein mitgeliefertes JSON-Objekt bei POST- oder PUT-Aufrufen könnte wie folgt aussehen:

{​
  “temperature“: 23.5,​
  “humidity“: 12.7,​
  “pressure“: 990.5,​
  “resistance“: 23.8,​
  "date“: “2023-06-10“,​
  “time“: “06:24:56“​
}​
Let’s Spring-boot

Für die eigentliche Magie in der Server-Anwendung sorgt Spring Boot 3. Laut der Spring-Seite gilt für Spring Boot:

"Das Spring Framework bietet ein umfassendes Programmier- und Konfigurationsmodell für moderne Java-basierte Unternehmensanwendungen – auf jeder Art von Einsatzplattform.

Ein Schlüsselelement von Spring ist die infrastrukturelle Unterstützung auf der Anwendungsebene: Spring konzentriert sich auf das "Klempnerhandwerk" von Unternehmensanwendungen, sodass sich die Teams auf die Geschäftslogik auf Anwendungsebene konzentrieren können, ohne unnötige Bindungen an bestimmte Bereitstellungsumgebungen."

Das Java-Framework integriert einen Webserver mit Servlet-Unterstützung (Tomcat oder optional Jetty), über den es die REST-API im Web beziehungsweise Netzwerk zur Verfügung stellt. Die ganze Servlet-Maschinerie bleibt Entwicklerinnen und Entwicklern erspart. Zudem bietet es eine Repository-Schnittstelle, mit deren Hilfe die REST-Endpunkte neue Einträge beispielsweise speichern, ändern, löschen oder abrufen. Außerdem sorgt es über Annotationen für das objekt-relationale Mapping zwischen der measurement-Datenbanktabelle und dem entsprechenden Java-Objekt.

In IntelliJ Ultimate findet sich Unterstützung für die Arbeit mit Docker und Spring Boot

In der Datei Main.java (siehe Listing unten) ist die Klasse Main als @SpringBootApplication annotiert. Das sorgt dafür, dass Spring Boot nach Komponenten und Entitäten sucht und weitere Handarbeiten automatisch erledigt. Gleichzeitig fungiert die Klasse auch als @RestController, weshalb sich in ihr REST-Endpunkte befinden müssen. Mittels der Annotation @RequestMapping("measurements/api") legt man fest, welches Prefix jeder REST-Endpunkt bekommen soll. Externe Aufrufe beginnen dann immer mit diesem Prefix, also zum Beispiel GET <hostname>:8080/measurements/api. Der Konstruktur der Klasse Main enthält als Parameter ein MeasurementRepository, über das die REST-Endpunkte Aktionen auf dem aktuellen persistierten Objekt durchführen, etwa um eine neue Messung in der Datenbank zu speichern:

public Main(MeasurementRepository measurementRepository) {​
        this.measurementRepository = measurementRepository;​
}​

Die Schnittstelle MeasurementRepository erzeugt Spring Boot automatisch und übergibt sie per Dependency Injection an den Konstruktor. Es ist dementsprechend als @Repository definiert und leitet sich von JpaRepository ab. Die zwei Typparameter von JpaRepository beziehen sich auf die Persistenzklasse für Datenbankeinträge (Measurement) und auf den Datentyp des Primärschlüssels (Integer):

@Repository​
public interface MeasurementRepository​
        extends JpaRepository<Measurement, Integer> {​
}​

Einer der definierten REST-Endpunkte ist etwa folgendes parametrisiertes GET:

@GetMapping("{id}")​
public Optional<Measurement> getMeasurementById(@PathVariable("id") Integer id)​

Die GetMapping-Annotation sorgt dafür, dass beim GET-Aufruf des Endpunkts mit der URL <hostname>:port/measurements/api/3 die Methode das entsprechende Datenbankobjekt mit Primärschlüssel 3 zurückliefert. Sie nimmt dabei das angesprochene MeasurementRepository zu Hilfe:

return measurementRepository.findById(id);

Wichtig in Zusammenhang mit REST-Endpunkten ist die Tatsache, dass bei Rückgaben von Ergebnissen Spring Boot dafür sorgt, diese zuvor in ein JSON-Objekt umzuwandeln – es wären im Übrigen auch andere Formate möglich. Zugleich erwartet jeder REST-Endpunkt, dass ihm entsprechende Messergebnisse im Body des HTTP-Pakets als JSON-Objekte übergeben werden. Das ist insbesondere bei POST und PUT notwendig, gilt aber nicht für in der URL angegebene Parameter wie etwa die gewünschte Id des "REST-Objektes" (siehe GET und DELETE). Letztere wird als Parameter in die URL integriert, zum Beispiel: localhost:8080/measurements/api/12

package de.stal;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@SpringBootApplication
@RequestMapping("measurements/api")
public class Main {

    private final MeasurementRepository measurementRepository;

    public Main(MeasurementRepository measurementRepository) {
        this.measurementRepository = measurementRepository;
    }

    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

    @GetMapping
    public List<Measurement> getMeasurement() {
        return measurementRepository.findAll();
    }

    @GetMapping("{id}")
    public Optional<Measurement> getMeasurementById(@PathVariable("id") Integer id){
        return measurementRepository.findById(id);
    }

    @PostMapping
    public void addMeasurement(@RequestBody NewMeasurementRequest request) {
        Measurement measurement = new Measurement();
        measurement.setDate(request.date);
        measurement.setTime(request.time);
        measurement.setTemperature(request.temperature);
        measurement.setHumidity(request.humidity);
        measurement.setPressure(request.pressure);
        measurement.setResistance(request.resistance);
        measurementRepository.save(measurement);
    }

    record NewMeasurementRequest(
            java.sql.Date date,
            java.sql.Time time,
            Double temperature,
            Double humidity,
            Double pressure,
            Double resistance
    ){}

    @DeleteMapping("{measurementId}")
    public void deleteMeasurement(@PathVariable("measurementId") Integer id) {
        measurementRepository.deleteById(id);
    }

    // assignment
    @PutMapping("{measurementId}")
    public void updateMeasurement(@PathVariable("measurementId") Integer id,
                               @RequestBody NewMeasurementRequest msmUpdate) {
        Measurement existingMeasurement = measurementRepository.findById(id)
                .orElseThrow();
        existingMeasurement.setDate(msmUpdate.date);
        existingMeasurement.setTime(msmUpdate.time);
        existingMeasurement.setTemperature(msmUpdate.temperature);
        existingMeasurement.setHumidity(msmUpdate.humidity);
        existingMeasurement.setPressure(msmUpdate.pressure);
        existingMeasurement.setResistance(msmUpdate.resistance);


        measurementRepository.save(existingMeasurement);
    }

}

Die Klasse Measurement.java (siehe Listing unten) definiert die eigentliche Entität, die über ein objektrelationales Mapping mit der Datenbank verbunden ist. Dementsprechend enthält die Klasse eine @Entity-Annotation.

Wer IntelliJ IDEA oder eine andere fortschrittliche IDE nutzt, kann "Boilerplate"-Code wie Setters, Getters, toString(), equals(), hashcode() und Konstruktoren von der IDE generieren lassen. Andernfalls ist manuelles Eintippen nötig, was sich bei späteren Refactoring-Maßnahmen als umständlich erweist.

Nicht zu vergessen: Die Klasse Measurement benötigt einen parameterlosen Konstrukteur mit leerem Rumpf, damit das objektrelationale Mapping von Spring Boot aus JSON-Nachrichten Java-Objekte generieren kann.

Die Datenfelder der Klasse Measurement entsprechen den gewünschten Attributen des Datenbankeintrags, in unserem Fall Temperatur, Feuchtigkeit, Luftdruck, Gaswiderstand, Datum und Zeit. Den Primärschlüssel Integer id lassen wir Spring Boot für das Datenbanksystem automatisch generieren. Dazu dienen die Annotationen: @Id, @SequenceGenerator und @GeneratedValue. Der Primärschlüssel soll mit 1 starten und bei jedem neuen Datenbankeintrag um 1 hochgezählt werden. Die Annotation @id weist das gleichnamige Datenfeld als Primärschlüssel aus.

package de.stal;

import jakarta.persistence.*;

import java.sql.Date;
import java.sql.Time;
import java.util.Objects;

@Entity
public class Measurement {

    @Id
    @SequenceGenerator(
            name = "measurement_id_sequence",
            sequenceName = "measurement_id_sequence",
            allocationSize = 1
    )
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "measurement_id_sequence"
    )
    private Integer id;
    private Double temperature;
    private Double humidity;
    private Double pressure;
    private Double resistance;
    private java.sql.Date date;
    private java.sql.Time time;

    public Measurement(Integer id, Double temperature, Double humidity, Double pressure, Double resistance, Date date, Time time) {
        this.id = id;
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        this.resistance = resistance;
        this.date = date;
        this.time = time;
    }

    public Measurement() {
    }

    @Override
    public String toString() {
        return "Measurement{" +
                "id=" + id +
                ", temperature=" + temperature +
                ", humidity=" + humidity +
                ", pressure=" + pressure +
                ", resistance=" + resistance +
                ", date=" + date +
                ", time=" + time +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Measurement that = (Measurement) o;
        return Objects.equals(id, that.id) && Objects.equals(temperature, that.temperature) && Objects.equals(humidity, that.humidity) && Objects.equals(pressure, that.pressure) && Objects.equals(resistance, that.resistance) && Objects.equals(date, that.date) && Objects.equals(time, that.time);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, temperature, humidity, pressure, resistance, date, time);
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Double getTemperature() {
        return temperature;
    }

    public void setTemperature(Double temperature) {
        this.temperature = temperature;
    }

    public Double getHumidity() {
        return humidity;
    }

    public void setHumidity(Double humidity) {
        this.humidity = humidity;
    }

    public Double getPressure() {
        return pressure;
    }

    public void setPressure(Double pressure) {
        this.pressure = pressure;
    }

    public Double getResistance() {
        return resistance;
    }

    public void setResistance(Double resistance) {
        this.resistance = resistance;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Time getTime() {
        return time;
    }

    public void setTime(Time time) {
        this.time = time;
    }
}

Um die (Web-Server-)Anwendung zu konfigurieren, gibt es eine YAML-Datei mit dem Namen application.yml im resources-Ordner:

server:
  port: 8080

#turn off the web server
spring:
  datasource:
    url: jdbc:postgresql://localhost:5332/measurement
    username: michael
    password: michael
  jpa:
    hibernate:
      ddl-auto: create-drop
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect
        format_sql: true
    show-sql: true
  main:
    web-application-type: servlet

Hier legen Entwickler und Entwicklerinnen unter anderem Port, Passwort und Benutzername fest, zudem die URL zum Zugriff auf die PostgreSQL-Datenbank. Benutzername und Passwort müssen mit der korrespondierenden Konfiguration in docker-compose.yml übereinstimmen. Mit ddl-auto weisen wir Spring Boot JPA an, die Tabelle measurement zu löschen, falls die Anwendung beziehungsweise Session terminiert (drop measurement). Über web-application-type: servlet bestimmt die Konfiguration, dass wir zum Bereitstellen unserer REST-API einen Webserver benötigen, der Java-Servlets unterstützt. Das können Tomcat oder Jetty sein.

Damit wären wir am Ende der notwendigen Java- und Konfigurationsdateien angekommen. Der Gesamtumfang aller Dateien liegt bei rund 250 Codezeilen zuzüglich Konfigurationsfestlegungen und inklusive der mittels IDE (IntelliJ IDEA) generierten Codes. Der Aufwand, um kleinere REST-APIs zu entwickeln, hält sich daher dank Spring Boot in Grenzen.

Fazit

Durch Spring Boot fällt es leicht, recht schnell und effizient eine REST-API zusammenzubauen. Natürlich gäbe es auch Alternativen wie Quarkus oder Micronaut, aber Spring Boot ist sehr verbreitet und besitzt eine große Community. Das Beispiel ist für die Übergabe von Messungen des BME688 festgelegt. Es ist allerdings sehr leicht, die Anwendung für andere Sensoren oder andere Zwecke auszulegen.

  • Denkbar ist zum Beispiel der Anschluss mehrerer Boards mit Sensoren. Dafür müssten Entwicklerinnen und Entwickler die Messungsobjekte mit dem Attribut Client-ID ausstatten sowie weitere beziehungsweise andere Attribute hinzufügen.
  • Denkbar wäre es auch, das Datenbanksystem und/oder die Spring-Anwendung in die Cloud (AWS, Azure) zu laden. Dafür bedarf es allerdings zuerst eines Sicherheitskonzepts, etwa mit Hilfe von OAuth2 und JWT (Java Web Token).
  • Auch weitere REST-Endpunkte wären möglich. Dementsprechend repräsentiert das hier beschriebene Beispiel lediglich einen von vielen möglichen Anwendungsfällen.

Während sich dieser Beitrag auf die Server-Seite fokussiert hat, beschreibt der in Kürze nachfolgende Teil 2, wie sich auf Microcontroller-Boards wie dem Arduino Giga die dazu passenden REST-Clients erstellen lassen.


URL dieses Artikels:
https://www.heise.de/-9179764

Links in diesem Artikel:
[1] https://github.com/ms1963/RESTCommunication
[2] https://jdbc.postgresql.org/
[3] https://www.docker.com
[4] https://www.postman.com/
[5] mailto:map@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 07. Juni 2023 um 14:43

Fernsteuerung per Computer: GPIO-Breakout-Boards als Schweizer Taschenmesser

Von heise online

(Bild: Adafruit)

GPIO-Breakout-Boards wie das Adafruit FT232H ermöglichen den Zugriff auf elektronische Schaltungen von einem Computer.

Um von einem Computer aus auf Elektronikkomponenten zuzugreifen, existieren verschiedene Wege. Zum einen lassen sich Mikrocontroller über USB dazwischenschalten, um beispielsweise auf Arduino-Boards oder Raspberry Pi mittels einer auf den Boards laufenden Software die Elektronik zu kontrollieren. Für Arduino-kompatible Boards lässt sich zu diesem Zweck eine Firmata-Firmware installieren, die den mehr oder weniger direkten Zugriff auf Ports des Boards ermöglicht.

Eine weitere Option ist die RESTful-Kommunikation von einem Computer zu einem autonomen Mikrocontroller-Board, um über diesen Umweg auf Elektronik zuzugreifen. Das Programm auf dem Board fungiert als Vermittler zwischen Computer und Elektronik.

Ein dritter Weg besteht darin, ein sogenanntes GPIO-Breakout-Board über USB an den betreffenden Computer anzuschließen. In diesem Fall können Anwendungen direkt auf die am Breakout-Board befindlichen GPIO-Ports zugreifen. Zudem implementiert ein GPIO-Breakout-Board meistens Unterstützung für Protokolle wie SPI oder I2C. Dadurch ist auch das Ansteuern etwas komplexerer Hardware – zum Beispiel Displays und Sensoren – möglich.

Das Adafruit FT232H GPIO Breakout Board

Ein solches GPIO-Breakout-Board ist das Adafruit FT232H Breakout Board Blinka, das zu Straßenpreisen von rund 15 bis 18 Euro erhältlich ist, etwa bei BerryBase [1]. Es gibt natürlich auch andere GPIO-Boards, aber das Untersuchte besitzt eine ausreichende Zahl von GPIO-Ports und unterstützt zudem UART, I2C, SPI, Bit-Bang und JTAG. Entwicklerinnen und Entwickler können es über Python vom Computer aus ansteuern. Zudem sind für das FT232H-Board viele Informationsquellen verfügbar.

Für meine Experimente habe ich die neueste Variante des Boards erworben, die über einen USB-C-Port und einen Stemma-QT-Konnektor verfügt, der den Anschluss entsprechender Komponenten mit STEMMA/QT- beziehungsweise Qwiic-Interface erlaubt.

Die neueste Version des Breakout-Boards bietet einen USB-C-Anschluss und einen Quiic/STEMMA-QT-Anschluss.

(Bild: Adafruit)

Die ältere Version des Boards kann lediglich mit einem Micro-USB-Anschluss aufwarten.

(Bild: Adafruit)

En detail

Das Board ist nach dem integrierten Chip benannt, einem FT232H von FTDI, der auch das komplette USB-Protokoll implementiert. Dadurch müssen sich Entwickler nicht mit systemnaher USB-Funktionalität herumschlagen. Im vielen Fällen ist keine Installation eines USB-Treibers auf dem Computer notwendig. Der FT232H unterstützt USB 2.0 Hi-Speed, was Übertragungsraten bis 480 MBit/s gewährleistet – im ebenfalls verfügbaren Full-Speed-Modus sind es stattdessen maximal 12 MBit/s. Die neue Boardversion besitzt einen USB-C-Port. Ein passendes Kabel findet sich nicht im Lieferumfang. Daher empfiehlt es sich, gleich ein entsprechendes Kabel mit zu bestellen, sofern nicht bereits vorhanden.

Der Chip-Kern arbeitet mit 1,8V, die Ein-/Ausgänge mit 3,3V. Letztere sind tolerant gegenüber 5V. Noch genauere Details finden sich auf dem Produktblatt des Chip-Herstellers [2].

Wie im Pinout-Diagramm ersichtlich (siehe obige Abbildungen), stellt die Adafruit-Lösung die GPIO-Ports D4-D7 sowie C0-C7 bereit.

Die Ports D0-D3 implementieren das SPI- oder das I2C-Protokoll. Das "oder" will sagen, dass zur Ansteuerung entweder I2C oder SPI verfügbar ist, aber nicht beides gleichzeitig.

Mit einem Schalter auf dem Board bestimmen Entwickler, ob sie I2C nutzen aber nicht SPI (Schalterstellung I2C auf on), oder ob sie SPI nutzen möchten aber nicht I2C (Schalterstellung I2C auf off). Im letzteren Fall gilt: D0 -> SCLK, D1 -> MOSI, D2 -> MISO, D3 -> CS0. Im ersteren Fall wiederum gibt es folgende Zuordnung: D0 -> SCL, D1 oder D2 -> SDA. Hierbei lässt sich einer der beiden Ports D1 und D2 nutzen, um das SDA-Signal von I2C zu übertragen. In der alten Version des Boards mussten Anwender für I2C noch den Port D1 mit dem Port D2 verdrahten, um dann D2 mit der eigentlichen Schaltung zu verbinden.

Installation

Zur Installation des Boards stellt Adafruit eine eigene Webseite mit Anleitung zur Verfügung [3]. Wichtig ist die Tatsache, dass die Programmierung auf dem Windows-, Mac- oder Linux-Computer eine Installation von Python 3 [4] und pip3 [5] erfordert.

Da Windows keine treiberlosen USB-Geräte unterstützt, müssen Anwender zunächst einen USB-Treiber von Zadig [6] installieren. Bei macOS und Linux ist das in den allermeisten Fällen nicht notwendig.

Danach folgen auf allen Betriebssystemen zum Zugriff über CircuitPython noch Installationen der libusb-Bibliothek sowie der speziellen Python-Bibliotheken pyftdi und adafruit-blinka – Blinka ist übrigens auch der Name des Breakout-Boards. Schließlich müssen noch udev-Rules (Linux only) festgelegt und eine Umgebungsvariable (alle Betriebssysteme) definiert werden. Diese Variable heißt BLINKA_FT232H und soll bei einem Wert von 1 das Vorhandensein eines Blinka-Boards signalisieren.

Wie bereits oben erwähnt, ist hier immer vorausgesetzt, dass auf dem Computer eine Installation von python3 und pip3 vorliegt.

Das Board wird übrigens ohne "vormontierte" Header ausgeliefert. Zunächst ist daher etwas Lötarbeit erforderlich.

Hier die verschiedenen Anleitungen:

Zur Ansteuerung von Schaltungen über das Breakout-Board Blinka muss dieses natürlich an den eigenen Computer angeschlossen sein. Softwaretechnisch dienen CircuitPython-Programme als Schnittstelle zum Board. Standard-Computer unter Windows, Linux, macOS verstehen zwar Python 3, aber wie können Entwickler CircuitPython nutzen? Dafür bedarf es zum einen der Blinka-Bibliothek für Python (adafruit-blinka) und entsprechender CircuitPython-Bibliotheken für die "ferngesteuerte" Hardware wie Sensoren, Bildschirme und dergleichen:

Der Computer benötigt eine Python3-Installation plus diverse Bibliotheken, um Schaltungen beziehungsweise Komponenten ansteuern zu können.

(Bild: Adafruit)

Da ich zum Test des Blinka-Boards einen Mac-Computer benutzt habe, folgen nun exemplarisch die für macOS notwendigen Installationsschritte im Detail:

Sollte noch keine Installation des Package Managers Homebrew vorhanden sein, installieren wir ihn mittels:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Anschließend ist die Installation von libusb mit Hilfe von Homebrew erforderlich:

brew install libusb

Danach die von pyftdi:

pip3 install pyftdi

Und im letzten Schritt das Installieren der eigentlichen Board-Bibliothek:

pip3 install adafruit-blinka

Nun sollte die Anwenderin die Umgebungsvariable BLINKA_FT232H mit 1 belegen:

export BLINKA_FT232H=1

Zu guter Letzt gilt es noch, die Python 3 REPL-Umgebung zu starten und schrittweise die folgenden zwei Anweisungen einzugeben:

import board
dir(board)

Verlief alles fehlerlos, gibt letztere Instruktion die Liste der verfügbaren Pins auf dem Terminal aus.

Fertig ist die Installation!

Zum Prüfen ob die Installation funktioniert, gibt es folgende Tests:

Zunächst ein Test, um sicherzustellen, dass das System das FT232H-Board erkennt:

from pyftdi.ftdi import Ftdi

Ftdi().open_from_url('ftdi:///?')

Normalerweise gibt es nur einen FTDI-Controller, weshalb die Ausgabe wie folgt aussehen könnte:

>>> from pyftdi.ftdi import Ftdi

>>> Ftdi().open_from_url('ftdi:///?')[Link auf https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/setup] [11]

Available interfaces:

ftdi://ftdi:232h:1/1 ()/code/p pcodePlease specify the USB device/code/p pDanach eine Verifikation, ob die Umgebungsvariable vorhanden und korrekt gesetzt ist:/p pcodeimport os/code/p pcodeos.environ["BLINKA_FT232H"]/code/p pDie Ausgabe müsste schlicht lauten:/p pre class="rte__tx--listing"codestrong´1´/strong/code/pre pWie gesagt, diese Beschreibung kratzt nur an der Oberfläche. Die genauen Anweisungen lassen sich a href="https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/setup" rel="external noopener" target="_blank"strongauf der Anleitungs-Website von Adafruit nachvollziehen [12]/strong/a./p pSollte es Probleme geben, finden sich auf der a href="https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/troubleshooting" rel="external noopener" target="_blank"strongAdafruit-Website Post-Install-Checks [13]/strong/a entsprechende Hinweise./p h3 class="subheading" id="nav_programmierung_3"Programmierung/h3 pIch spare mir Beispiele für das obligatorische LED-Blinken oder das Erkennen des Zustands eines Druckknopfes. Stattdessen soll der Anschluss eines a href="https://sensirion.com/de/produkte/katalog/SHT40" rel="external noopener" target="_blank"strongSensirion SHT40 [14]/strong/a als Beispiel dienen./p pDieser Sensor kostet nur wenige Euro und misst Temperatur und Feuchtigkeit relativ präzise. Die typische Genauigkeit bei der relativen Luftfeuchtigkeit beträgt 1,8% RH und bei der Temperatur 0,2°C. Verwendung findet in diesem Zusammenhang ein Adafruit-Board mit I2C-Anschluss. Das Messen kann entweder mit oder ohne Heizen (-gt;codesht.mode/code) erfolgen. Für das Programmbeispiel habe ich auf das Heizen verzichtet. Da es sich um ein I2C-basiertes Sensorboard handelt, ist der I2C-Switch des FT232H auf ON zu stellen./p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="522" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/3/5/4/2/8/9/0/BildDerSchaltung-3584313b6978b464.JPG" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/3/5/4/2/8/9/0/BildDerSchaltung-3584313b6978b464.JPG 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/3/5/4/2/8/9/0/BildDerSchaltung-3584313b6978b464.JPG 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/3/5/4/2/8/9/0/BildDerSchaltung-3584313b6978b464.JPG 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"An das Breakout-Board wird über ein Qwiic/STEMMA-QT-Kabel der Sensirion SHT40 angeschlossen./div /figcaption /figure pDer Sensor benötigt nach jeder Messung etwa vier Sekunden Verschnaufpause – zwei Sekunden bei der Temperaturmessung und vier Sekunden bei der Feuchtigkeitsmessung. Deshalb enthält die while-Schleife ein codesleep(4)/code./p pVor dem Programmstart müssen Entwickler noch die benötigte Bibliothek von Adafruit installieren:/p pre class="rte__tx--listing"pip3 install adafruit-circuitpython-sht4x/pre pDas vorliegende Programmbeispiel stammt im Original von Adafruit./p h3 class="subheading" a-code language="python" pre class="rte__tx--listing listing"codeimport time # zum Verzögern der Ausgaben import board # zur Ausgabe über FT232H import adafruit_sht4x # Einbinden der Bibliothek für den Sensor i2c = board.I2C() # Am I2C-Anschluss (SDA/SCL des FT232H) hängt ein Adafruit SHT40-Breakout-Board sht = adafruit_sht4x.SHT4x(i2c) print("SHT4X mit folgender Seriennummer entdeckt: ", hex(sht.serial_number)) sht.mode = adafruit_sht4x.Mode.NOHEAT_HIGHPRECISION # ohne Heizen! # alternativ mit: sht.mode = adafruit_sht4x.Mode.LOWHEAT_100MS print("Augenblicklicher Modus: ", adafruit_sht4x.Mode.string[sht.mode]) while True: temperature, relative_humidity = sht.measurements print("Temperatur: %0.1f C" % temperature) print("Feuchtigkeit: %0.1f %%" % relative_humidity) print("") time.sleep(4) # 4 Sekunden Verzögerung/code/pre /a-code /h3 pDie Bildschirmausgabe gestaltet sich wenig spannend wie folgt:/p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="463" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/3/5/4/2/8/9/0/BildBildschirmausgabeBeispiel-59de146e93e58830.PNG" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/3/5/4/2/8/9/0/BildBildschirmausgabeBeispiel-59de146e93e58830.PNG 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/3/5/4/2/8/9/0/BildBildschirmausgabeBeispiel-59de146e93e58830.PNG 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/3/5/4/2/8/9/0/BildBildschirmausgabeBeispiel-59de146e93e58830.PNG 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Bildschirmausgabe mit den Messwerten des Sensirion SHT40./div /figcaption /figure h3 class="subheading" id="nav_vorsicht_geboten_4"Vorsicht geboten/h3 pEine Warnung müssen Entwicklerinnen und Entwickler unbedingt berücksichtigen. Beim Anschluss von Komponenten an das Breakout-Board sollten sie sicherstellen, dass die jeweilige Schaltung keine Gefahr für den USB-Port darstellt. Ansonsten könnte eine Überlastung am USB-Port des Computers diesen in Mitleidenschaft ziehen. Adafruit weist darauf hin, dass das Board maximal 400-500mA aus dem USB-Port ziehen darf. Dafür gibt es diverse Abwehrmaßnahmen – darunter: Testen, die Absicherung gegenüber induktiver Lasten mittels Dioden, das Begrenzen von Stromstärken mittels Widerständen. Wer das vergisst, könnte den angeschlossenen Computer schädigen. Wie heißt es so schön: Vorsicht ist die Mutter der Porzellankiste./p h3 class="subheading" id="nav_fazit_5"Fazit/h3 pGPIO-Breakout-Boards wie das Adafruit FT232H bieten eine sehr gute Möglichkeit, von Computern aus direkt auf Elektronik zuzugreifen, ohne ein Mikrocontroller-Board dazwischenschalten zu müssen. Das hat natürlich auch Grenzen hinsichtlich der möglichen Anwendungen. Beispielsweise erlauben Mikrocontroller-basierte Lösungen im Vergleich zu ihren PC-Pendants Echtzeitanforderungen und sind hinsichtlich der Verwendung verschiedener Protokolle wesentlich flexibler. Auf der anderen Seite besitzt eine Computer-gestützte Lösung ebenfalls Vorteile. Chip-Hersteller FTDI nennt unter anderem die Ansteuerung von Kameraschnittstellen, Bar-Code-Lesern, Settop-Boxen, Flash-Card-Lesern, MP3-Geräten sowie industrielle Anwendungen als mögliche Beispiele./p pSchön wäre neben der Unterstützung für CircuitPython das Bereitstellen von C- beziehungsweise C++-Bibliotheken, um das Board auch in entsprechenden Anwendungen zu nutzen. Das ist allerdings Jammern auf hohem Niveau. Für die Arten von Anwendungen, die für einen FT232H in Frage kommen, reicht Python völlig aus. Speziell für das Rapid Prototyping eigener Experimente weist Python einige Vorteile auf./p p !-- RSPEAK_STOP -- !-- RSPEAK_START -- /p hr p strongURL dieses Artikels:/strongbr smallcodehttps://www.heise.de/-7091889/code/small /p p strongLinks in diesem Artikel:/strongbr smallcodestrong[1]/strongnbsp;https://www.berrybase.de/adafruit-ft232h-breakout-general-purpose-usb-zu-gpio-spi-i2c/code/smallbr smallcodestrong[2]/strongnbsp;https://ftdichip.com/products/ft232hq//code/smallbr smallcodestrong[3]/strongnbsp;https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/setup/code/smallbr smallcodestrong[4]/strongnbsp;https://www.python.org/downloads//code/smallbr smallcodestrong[5]/strongnbsp;https://www.activestate.com/resources/quick-reads/how-to-install-and-use-pip3//code/smallbr smallcodestrong[6]/strongnbsp;https://zadig.akeo.ie//code/smallbr smallcodestrong[7]/strongnbsp;https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/windows/code/smallbr smallcodestrong[8]/strongnbsp;https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/linux/code/smallbr smallcodestrong[9]/strongnbsp;https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/mac-osx/code/smallbr smallcodestrong[10]/strongnbsp;https://cdn-learn.adafruit.com/downloads/pdf/circuitpython-on-any-computer-with-ft232h.pdf/code/smallbr smallcodestrong[11]/strongnbsp;https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/setup/code/smallbr smallcodestrong[12]/strongnbsp;https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/setup/code/smallbr smallcodestrong[13]/strongnbsp;https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/troubleshooting/code/smallbr smallcodestrong[14]/strongnbsp;https://sensirion.com/de/produkte/katalog/SHT40/code/smallbr smallcodestrong[15]/strongnbsp;mailto:map@ix.de/code/smallbr /p p class="printversion__copyright" emCopyright © 2023 Heise Medien/em /p pstronga href="https://blockads.fivefilters.org"Adblock test/a/strong a href="https://blockads.fivefilters.org/acceptable.html"(Why?)/a/p

  • 10. Mai 2023 um 10:25

Javas Modulsystem: Hilfe, meine Abhängigkeiten sind keine Java-Module!

Von heise online

(Bild: Shutterstock)

Mit Java kann man Anwendung mittlerweile gut modularisieren, muss aber auch Abhängigkeiten beachten. Wenn diese keine Java-Module sind, wird es spannend.

In einem vorherigen Post habe ich über eine minimale Unterstützung für das Java Modulsystem (Java Platform Module System, JPMS) geschrieben und wie man helfen kann, sie zu erreichen. Nun kann es aber immer wieder passieren, dass Bibliotheken das Java-Modulsystem nicht unterstützen und es auch nicht absehbar ist, dass diese in Zukunft wenigstens als „Automatische Module“ verfügbar sein werden.

Wenn man seinen eigenen Code auf das JPMS umstellen will und von solchen Bibliotheken abhängig ist, muss man teilweise in die Trickkiste greifen. In diesem Post möchte ich einmal auf genau solche Abhängigkeiten eingehen und schauen, wie man damit umgehen kann.

Gradle-Plug-in als Abhilfe

Auch wenn ich mich eher bei Maven zu Hause fühle, habe ich erst neulich an der Umstellung eines großen Gradle-Projekts auf Java-Module gearbeitet. Da das Projekt Open Source ist, kann es einfach bei GitHub eingesehen werden [1]. In diesem Projekt gab es zu Beginn des Umbaus eine Vielzahl von Abhängigkeiten, die nicht das Java-Modulsystem unterstützt haben. Bei einigen konnten wir eine nachhaltige Lösung erzielen, indem wir direkt Pull Requests (PR) bei den jeweiligen Projekten erstellt haben, um diese um einen Automatic-Module-Name zu ergänzen. Wie man das einfach über ein Maven- oder Gradle-Plug-in erreichen kann, habe ich bereits im vorherigen Post zu dem Thema beschrieben. Ein Beispiel eines solchen PR kann hier [2] gefunden werden.

Nun gibt es aber auch Abhängigkeiten, bei denen man einen solchen PR nicht einfach stellen kann oder bei denen der PR nicht angenommen wird. Vielleicht hat man auch eine Abhängigkeit, deren Weiterentwicklung eingestellt wurde. In allen diesen Fällen wird eine andere Umsetzung benötigt. Im Grunde muss man sich selbst darum kümmern, aus den Abhängigkeiten Java-Module zu erstellen. Hierfür gibt es unterschiedliche Möglichkeiten. Man kann beispielsweise händisch einen Automatic-Module-Name-Eintrag zum Manifest des Jar hinzufügen und die abgeänderte Version dann in einem internen Maven Repository hosten. Für das erwähnte Gradle-Projekt haben wir auf das „extra-java-module-info“-Plug-in von Jendrik Johannes zurückgegriffen. Dieses als Open Source verfügbare Plug-in [3] erlaubt es, zur Build-Zeit einen Automatic-Module-Name Eintrag zu Abhängigkeiten hinzuzufügen. Konkret wird das Plug-in wie in folgendem Beispiel genutzt, wobei bei jedem automaticModule(…) Aufruf der Gradle Identifier der Abhängigkeit als erster Parameter und der zu nutzende Modulname als zweiter Parameter übergeben werden:

plugins {
    id("org.gradlex.extra-java-module-info")
}

extraJavaModuleInfo {
    failOnMissingModuleInfo.set(true)

	automaticModule("io.prometheus:simpleclient", 
	                "io.prometheus.simpleclient")
	automaticModule("io.prometheus:simpleclient_common",
	                "io.prometheus.simpleclient_common")
	automaticModule("io.prometheus:simpleclient_httpserver", 
	                "io.prometheus.simpleclient.httpserver")
}

Zusammen mit dem Autor des Plug-ins konnten wir in einem sehr produktiven Austausch das Ganze sogar noch deutlich erweitern. Das Plug-in konnte neben automatischen Modulen schon immer Module mit einer module-info.java erstellen. Hierbei musste man allerdings händisch Angaben wie exports definieren. Durch neue Funktionalitäten kann man nun ein Modul so definieren, dass dessen vollständigen Packages exportiert werden (siehe weitere Infos [4]). Das hat den großen Vorteil, dass man nicht mit automatischen Modulen arbeiten muss, die einige Besonderheiten mich sich bringen, da unter anderem alle automatischen Module zu den „required“ Abhängigkeiten eines Moduls hinzugefügt werden, sobald ein automatischen Modul als „required“ in der module-info.java angegeben ist (siehe Java Spec [5]). Hier noch einmal ein großes Dankeschön an Jendrik Johannes als Maintainer der Bibliothek. Unsere Zusammenarbeit hat aus meiner Sicht extrem gut die Vorteile von Open Source aufgezeigt. Für alle, die hier noch tiefer einsteigen möchten, hat Jendrik mehrere Videos zu diesem Thema und anderen Themen rund um Gradle kostenlos auf YouTube gehostet [6].

Ein Problem bleibt

Ein letztes großes Problem kann aber auch mit den hier vorgestellten Umsetzungen nicht behoben werden: Sobald ein JAR gegen die package split constraints des Java-Modulsystems verstößt, kann es nicht zum modulepath hinzugefügt werden. In diesem Fall müssen noch deutlich weitreichende Schritte vorgenommen werden. Diesen Punkt werde ich mich aber in einem zukünftigen Beitrag zuwenden.


URL dieses Artikels:
https://www.heise.de/-7536607

Links in diesem Artikel:
[1] https://github.com/hashgraph/hedera-services
[2] https://github.com/offbynull/portmapper/pull/48
[3] https://github.com/gradlex-org/extra-java-module-info
[4] https://github.com/gradlex-org/extra-java-module-info/issues/38
[5] https://docs.oracle.com/javase/specs/jls/se16/html/jls-7.html#jls-7.7.1
[6] https://www.youtube.com/@jjohannes
[7] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 09. Mai 2023 um 10:03

Developer: Natürliche Feinde der Softwarearchitektur?

Von Eberhard Wolff
Creative,Code,Skull,Hologram,On,Modern,Computer,Background,,Cybercrime,And

(Bild: Pixels Hunter/Shutterstock.com)

Softwarearchitektur beeinflusst den Erfolg eines Projekts erheblich. Aber ausgerechnet "gute" Entwickler und Entwicklerinnen können Feinde der Architektur sein.

Warum ist Softwarearchitektur überhaupt so wichtig? Sie hilft uns, große Systeme zu implementieren. Durch die Strukturierung von Code in Module können wir sicherstellen, dass Entwicklerinnen und Entwickler für Änderungen nur das jeweils zu ändernde Modul im Detail verstehen müssen. Von anderen Modulen ist nur oberflächliches Wissen notwendig, beispielsweise über die Schnittstelle. Dieses Prinzip wird als "Information Hiding" bezeichnet: Details sind in den Modulen versteckt und können mit wenig Einfluss auf andere Module geändert werden. So lassen sich Module idealerweise in Isolation verstehen und ändern. Wenn die Architektur besonders gelungen ist, können Entwicklerinnen also mit wenig Wissen und daher besonders einfach Änderungen an der Software vornehmen.

Unter "guten" Developern möchten wir uns hier Personen vorstellen, die auch komplizierte Systeme verstehen und weiterentwickeln können. Solche Personen können auch mit Architektur-Fehlschlägen umgehen, bei denen Änderungen nicht so einfach sind und gegebenenfalls schwer zu verstehende Auswirkungen haben – manchmal auf völlig andere Stellen des Systems. Vielleicht finden sie es sogar intellektuell herausfordernd, sich mit solchen Problemen zu beschäftigen, und es macht ihnen Spaß. Außerdem sorgen diese Umstände nicht nur für einen sicheren Job, sondern auch für Prestige. Schließlich sind diese Personen oftmals die Einzigen, die wichtige Systeme noch ändern können und so für das Geschäft einen sehr einen hohen Wert haben.

Wer unleserlichen Code schreibt, gilt als kompetent

Hinweise auf ein solches Verständnis von "guten" Entwicklern und Entwicklerinnen finden sich auch anderswo: Wer beispielsweise im Code die Feinheiten von einer Programmiersprache wie Java nutzt, die in einer Zertifizierung abgefragt werden, erstellt nicht besonders einfach zu verstehenden und zu ändernden Code, sondern gerade solchen, der die Features voll ausreizt und sich auf spezielle Eigenschaften der Sprache verlässt. Der Code ist besonders schwierig zu verstehen und damit zu ändern. Dennoch ist eine solche Zertifizierung als ein Hinweis auf das Können der Developer anerkannt. Wer also besonders unleserlichen Code schreiben oder lesen kann, gilt demnach als besonders gut.

Solche Entwickler und Entwicklerinnen mögen vielleicht "akademische" Architekturansätze nicht und bevorzugen eine "pragmatische" Herangehensweise. Schließlich profitieren sie von der Situation sogar. Bis zu einer gewissen Kompliziertheit funktioniert das ja auch. Bei "wirklich guten" Developern führt das bis zu einer erschreckend hohen Kompliziertheit. Sie verstehen dann Systeme, die für Außenstehende ein Mysterium sind. Dann fällt die Arbeit der Softwarearchitekten und -architektinnen aber vermutlich nicht auf fruchtbaren Boden. Schließlich kann man das System ja weiterentwickeln – warum es also besser strukturieren? In der Tat kann es passieren, dass die Architektin schließlich sogar das Team verlässt, um eine andere Position zu finden, wo ihre Mühen sinnvoller scheinen. Und daher sind "gute" Developer die natürlichen Feinde der Softwarearchitektur.

Was ist echte Kompetenz?

Das Problem ist das Verständnis, wann Entwicklerinnen als "gut" im Sinne von kompetent gelten. Natürlich müssen Entwickler Technologien verstehen. Es ist sicher vorteilhaft, wenn sie auch mit kompliziertem Code umgehen können, aber sie sollten solche Situationen vermeiden und auf keinen Fall auf sie hinarbeiten. Wirklich gute Developer arbeiten am liebsten an einfachem Code. Sie haben gerade eine Aversion gegen komplizierten Code – und dann haben Entwicklerinnen und "saubere" Architektur dasselbe Ziel.

Wir können in Projekten eine Umgebung schaffen, in der sich "saubere" Architektur durchsetzen kann. Dazu sollten wir Developer nicht beglückwünschen, weil sie eine komplizierte Änderung ganz alleine umgesetzt haben. Stattdessen sollte die Frage im Vordergrund stehen, wie sich solche komplizierten Änderungen in Zukunft vermeiden lassen und wie mehr Personen dazu befähigt werden können, solche Änderungen durchzuführen. Um die Entwicklung guter Softwarearchitektur zu fördern, sollten wir positive Arbeitsweisen belohnen und negative korrigieren. Statt den Fokus auf das individuelle Können eines Entwicklers beim Umgang mit kompliziertem Code zu legen, sollten wir uns auf die Qualität des Codes und die Umsetzung der Architektur konzentrieren.

Wichtig ist auch ein breites Interesse an Themen, die nicht mit den rein technischen Aspekten der Entwicklung zu tun haben. Das hilft dabei, die Domäne, die Anforderungen sowie die Nutzerinnen und Nutzer zu verstehen und die richtigen Features zu implementieren. Dazu muss man aber ein originäres Interesse an der Domäne und der Fachlichkeit haben – Personen mit einem breiten Interessenspektrum fällt das leichter.

tl;dr

Softwarearchitektur ist ein wichtiges Mittel, um die Kompliziertheit von Software einzudämmen. Developer, die auch mit komplizierten Systemen umzugehen vermögen, könnten einem solchen Architekturverständnis ablehnend gegenüberstehen.


URL dieses Artikels:
https://www.heise.de/-8971097

Links in diesem Artikel:
[1] mailto:sih@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 20. April 2023 um 18:52

Programmiersprache Java: Null-Fehler mit statischer Analyse aufspüren

Von heise online

(Bild: Shutterstock)

NullPointerExceptions sind mit die häufigste Fehlerquelle in Java. Durch statische Codeanalyse kann man diese Fehler deutlich minimieren.

Neue Projekte bringen neue Herausforderungen und neues Wissen mit sich. In meinem aktuellen Projekt [1] habe ich vor Kurzem eine Definition zum Umgang von null-Checks bei der statischen Codeanalyse erstellt. Vielen im Projekt war es wichtig, dass Parameter nicht nur zur Laufzeit beispielsweise durch Objects.requireNonNull(…)) überprüft werden, sondern auch direkt beim Kompilieren. Daher haben wir beschlossen, hier auch auf statischen Codeanalyse zur Überprüfung des Umgangs mit null zu setzen.

Statische Codeanalyse

Bevor wir uns auf die verschieben Annotation und Checker Libraries stürzen, die es für Java gibt, möchte ich einmal kurz erläutern, worum es sich bei einer statischen Codeanalyse handelt. Hierbei wird der Programmcode beim Kompilieren durch ein Tooling überprüft. Das aktuell gängigste Tool in Java ist sicherlich SpotBugs, das sich in Builds mit Maven oder Gradle einbinden lässt und dessen Ergebnisse auch automatisiert auf Plattformen wie SonarCloud veröffentlicht werden können. Mit einer statische Codeanalyse kann man Probleme wie einen Speicherüberlauf, eine Endlosschleife oder "Out of Bound“-Fehler finden. Ein einfaches Beispiel ist eine Division durch 0. Sollte so etwas im Code vorkommen, kann die Analyse eine Warnung liefern oder je nach Konfiguration den kompletten Build fehlerhaft beenden. In unserem Projekt haben wir einen solchen Check in GitHub Actions, das die Ergebnisse direkt in SonarCloud [2] und einem Pull Request anzeigt.

Der korrekte Umgang mit null

Ein Problem beim Programmieren mit Java ist sicherlich der Umgang mit null. Wobei ich persönlich klar die Meinung vertrete, dass null seine Berechtigung hat, auch wenn Tony Hoare, der Erfindern der null-Referenz in der Programmierung, hierüber mittlerweile als ein „Billion-Dollar Mistake“ spricht

Allerdings kann man in Java nicht nativ definieren, ob ein Parameter null sein darf. Das hat man mittlerweile versucht, über verschiedene Mittel in der Klassenbibliothek zu lösen. Beispiele hierfür sind java.util.Optional, Objects.requireNonNull(…) oder auch JSR305 [3].

Ein anschauliches Beispiel für eine Programmiersprache, die eine native Unterstützung für null-Referenzen hat, ist Kotlin. Sie unterscheidet explizit zwischen nullable-Referenzen und nonnull-Referenzen. Hierbei sind Letztere der Standard, wobei einer Variablen mit einer solchen Referenz nie null zugewiesen werden kann. Benötigt man eine Variable, die null umfassen kann, muss man mit einer nullable-Referenz arbeiten. Diese wird über das ? Zeichen angegeben. Der folgende Code beinhaltet ein Kotlin Beispiel für beide Referenzen:

var a: String = "abc" // Regular initialization means
                      // non-null by default
a = null // compilation error

var b: String? = "abc" // can be set to null
b = null // ok

Da es eine solche native Unterstützung in Java nicht gibt, versucht man sie über statische Codeanalyse so gut wie möglich zu integrieren. Generell werden hier zwei Annotationen benötigt, wobei eine (@Nullable) definiert, dass ein Wert beziehungsweise eine Variable null sein kann, und die andere Annotation definiert, dass ein Wert oder eine Variable nie null sein darf (@NonNull).

Zum Verständnis soll ein Code Beispiel dienen, das eine Methode definiert und per Annotation die Information hinzufügt, dass der Rückgabewert der Methode nie null sein kann:

@NonNull String getName() {
    if(isUnique()) {
        return „Item „ + getId();
    } else {
        return null;
    }
}

Wie man in der Implementierung der Methode sehen kann, ist es durchaus möglich, dass sie null zurückgibt. Das wär ein Fall, in dem die statische Codeanalyse eine Verletzung aufzeigt. Wer möchte, kann beispielsweise IntelliJ so konfigurieren, dass es solche Probleme direkt anzeigt.

Der folgende Code, der die @Nullable Annotation verwendet, führt zu einer Warnung in der Analyse:

void check(@Nullable String value) {
    Objects.hash(value.toLowerCase());
}

In diesem Beispiel wird durch die Annotation @Nullable für die Variable value definiert, dass diese den Wert null haben kann. Dass der Code allerdings direkt auf die Variable zugreift, führt potenziell zu einer NullPointerException zur Laufzeit. Auch das würde durch die statische Codeanalyse ausgewertet und als Problem ausgegeben.

Der Einbau in das eigene Projekt

Wer eine solche statische Codeanalyse im eigenen Projekt integrieren möchte, muss ein paar einfache Voraussetzungen schaffen. Als Erstes muss man sich für eins oder mehrere Analysetools entscheiden. Hier empfehle ich Spotbugs [4], das der Nachfolger von Findbugs ist. Das Tool kann entweder über die Kommandozeile oder integriert in einen Gradle oder Maven Build gestartet werden. Um die gefundenen Probleme zu analysieren, kann man sich diese entweder im Spotbugs eigenen Swing-Client anschauen oder beispielsweise als HTML-basierte Übersicht als Bestandteil einer generierten Maven-Site mittels des Maven site-Ziels. Man kann das Tool so konfigurieren, dass es die Ergebnisse beispielsweise in ein Sonar beziehungsweise die SonarCloud hochlädt.

Wer @Nullable- und @NonNull-Annotationen im Projekt nutzen möchte, benötigt eine Library, die die Annotation bereitstellt. Das eigene Projekt muss nur zur Compile-Zeit von der Library abhängig sein. Auch hier gibt es (leider) eine ganze Fülle an Bibliotheken, die Annotationen bereitstellen. Die einzelnen Libraries basierend auf ihren Vor- und Nachteilen zu beleuchten, wird Bestandteil eines eigenen Posts sein. Daher empfehle ich zunächst Spotbugs Annotations als Abhängigkeit, die man unter den folgenden Maven-Koordinaten finden kann:

<dependency>
    <groupId>com.github.spotbugs</groupId>
    <artifactId>spotbugs-annotations</artifactId>
    <version>4.7.3</version>
</dependency> 

Die Fülle an Tools und Libraries macht es einem bedauerlicherweise nicht leicht, die perfekte und zukunftsorientierte Kombination zu finden. Als ich tiefer in das Thema eingetaucht bin, war ich erschrocken, dass vieles in diesem Bereich noch immer nicht durch Standards oder allgemein genutzte Best Practices definiert ist. Zwar gab es hier verschiedene Ansätze wie etwa mit demJSR305 [5], aber diese sind immer irgendwann im Sande verlaufen und werden heute teils in einem wilden Mix genutzt. Deswegen werde ich auch diesem Problem in naher Zukunft einen eigenen Post widmen.


URL dieses Artikels:
https://www.heise.de/-7351944

Links in diesem Artikel:
[1] https://github.com/hashgraph/hedera-services
[2] https://sonarcloud.io/project/overview?id=com.hedera.hashgraph%3Ahedera-services
[3] https://jcp.org/en/jsr/detail?id=305
[4] https://spotbugs.github.io
[5] https://jcp.org/en/jsr/detail?id=305
[6] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 18. April 2023 um 15:12

Livestream-Special von the native web: enterJS, Gäste und Gewinnspiel

Von heise online

(Bild: Andrey VP/Shutterstock.com)

Der Livestream bringt am Mittwoch um 18 Uhr spannende Einblicke und Hintergründe zur enterJS, interessante Gespräche mit Gästen und ein Gewinnspiel.

Auf dem YouTube-Kanal der the native web GmbH [1] findet alle drei Wochen – immer am Mittwochabend um 18 Uhr – ein Livestream zu verschiedenen Themen rund um die Softwareentwicklung statt. Meistens programmiere ich live, gelegentlich gibt es aber auch andere Formate wie ein Ask-me-Anything (AMA) oder Ähnliches.

Interessante Gäste …

Der nächste Livestream findet am Mittwoch, 19. April statt, und es gibt ein ganz besonderes Highlight: Er dreht sich um die enterJS-Konferenz [2], eine der im deutschsprachigen Raum bedeutendsten Veranstaltungen rund um JavaScript und Webentwicklung, die am 21. und 22. Juni 2023 in Darmstadt stattfinden wird.

Anlässlich des zehnjährigen Jubiläums erwarten wir interessante Gäste aus dem Programmbeirat der enterJS: Zum einen Maika Möbus, Redakteurin bei der iX und bei heise Developer, zum anderen Melanie Andrisek, Technikjournalistin und Lektorin im dpunkt.verlag. Beide werden spannende Einblicke in die Welt der JavaScript- und Webentwicklung sowie in die Organisation der enterJS geben.

… und ein Gewinnspiel

Zum ersten Mal in unserer Livestream-Geschichte veranstalten wir außerdem ein Gewinnspiel. Zu gewinnen gibt es als Hauptpreis ein Freiticket für die enterJS 2023, ein iX-Plus-Abo sowie dreimal jeweils ein Buch aus dem Sortiment des dpunkt.verlag. Die Teilnahme wird ausschließlich während des Livestreams möglich sein, Voraussetzung sind ein Mindestalter von 18 Jahren und ein YouTube-Account.

Wir freuen uns auf Eure Teilnahme am Livestream am 19. April um 18 Uhr [4] und hoffen, dass Ihr genauso gespannt seid wie wir! Nutzt die Gelegenheit, um Eure Fragen und Kommentare im Livestream oder vorab auf Twitter [5] zu hinterlassen. Bis dahin, bleibt neugierig und wir sehen uns im Livestream!


URL dieses Artikels:
https://www.heise.de/-8964534

Links in diesem Artikel:
[1] https://www.youtube.com/@thenativeweb
[2] https://enterjs.de/
[3] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[4] https://www.youtube.com/watch?v=l2uZL4UXXUg
[5] https://twitter.com/thenativeweb
[6] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 17. April 2023 um 11:18

Mikrocontroller-Board: Das neue Arduino-Board Giga R1 WiFi

Von heise online
!-- RSPEAK_STOP -- figure class="aufmacherbild" img src="https://heise.cloudimg.io/cdn/n/n/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/BoardMitBlinkenderLED-f4ae17bc9d5347eb.gif" srcset="https://heise.cloudimg.io/cdn/n/n/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/BoardMitBlinkenderLED-f4ae17bc9d5347eb.gif 700w, https://heise.cloudimg.io/cdn/n/n/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/BoardMitBlinkenderLED-f4ae17bc9d5347eb.gif 1050w, https://heise.cloudimg.io/cdn/n/n/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/BoardMitBlinkenderLED-f4ae17bc9d5347eb.gif 1200w" sizes="(min-width: 80em) 43.75em, (min-width: 64em) 66.66vw, 100vw" alt class="img-responsive" figcaption class="akwa-caption" p class="caption akwa-caption__text"Das Arduino Gioga R1 WiFi Board ist das bisher leistungsstärkste Board in der Familie von Arduino-Boards für Maker/p p class="source akwa-caption__source"(Bild:nbsp;(c) arduino.cc)/p /figcaption /figure !-- RSPEAK_START -- p strongDas neue Board Arduino Giga R1 WiFi hat denselben Formfaktor wie die Mega-Boards von Arduino, denen es aber in allen Belangen technisch überlegen ist./strong /p pWeil es gerade en vogue zu sein scheint, starte ich mit dem obligatorischen Hintergrundwissen von ChatGPT zum Giga R1. Meine Anfrage an ChatGPT lautete "Schreibe einen Artikel zum Arduino Giga R1":/p p"Der Arduino Giga R1 ist eine Weiterentwicklung der beliebten Arduino-Plattform, die speziell für den Einsatz in professionellen und industriellen Anwendungen entwickelt wurde. Diese neueste Version des Arduino-Boards bietet zahlreiche Verbesserungen und Funktionen, die es zu einer leistungsstarken und flexiblen Lösung für eine Vielzahl von Projekten machen./p pEine der auffälligsten Verbesserungen beim Arduino Giga R1 ist seine erhöhte Leistungsfähigkeit. Das Board ist mit einem leistungsstarken 32-Bit-ARM-Mikrocontroller ausgestattet, der in der Lage ist, hohe Rechengeschwindigkeiten zu erreichen und eine Vielzahl von Anwendungen zu unterstützen. Dies ermöglicht es dem Arduino Giga R1, komplexe Anwendungen wie Bild- und Spracherkennung sowie maschinelles Lernen zu unterstützen./p pEine weitere wichtige Verbesserung beim Arduino Giga R1 ist seine erweiterte Konnektivität. Das Board verfügt über eine Vielzahl von Schnittstellen, einschließlich Ethernet, USB, CAN-Bus und RS485. Diese Schnittstellen ermöglichen es dem Board, mit anderen Geräten und Systemen zu kommunizieren und eine nahtlose Integration in eine breite Palette von Anwendungen zu ermöglichen./p pDarüber hinaus verfügt der Arduino Giga R1 über eine umfangreiche Bibliothek von Bibliotheken und Tools, die es Entwicklern erleichtern, Anwendungen für das Board zu erstellen. Diese Bibliotheken umfassen eine Vielzahl von Funktionen, einschließlich Sensorsteuerung, Datenerfassung, Datenanalyse und drahtloser Konnektivität. Dies ermöglicht es Entwicklern, komplexe Anwendungen schnell und einfach zu erstellen und anzupassen."/p pDoch damit genug zu den erstaunlich präzisen ChatGPT-Erkenntnissen./p h3 class="subheading" id="nav_warum_giga__0"Warum Giga?/h3 pDer Name "Giga" soll wohl darauf hinweisen, dass das neue Mikrocontroller-Board in allen Belangen wesentlich mehr leisten kann als ein Arduino Mega-Board. Das betrifft die eingesetzten Prozessoren, die Art und Zahl der Schnittstellen und etliches mehr. Arduino Giga und Mega haben den Formfaktor gemeinsam. Zum detaillierten Leistungsspektrum des Giga komme ich später noch. Auch vom Preislichen (68,70 Euro im offiziellen Arduino-Store) ähnelt der Arduino Giga mehr seinen Arduino-Pro-Cousins aus der Portenta-Serie und reiht sich damit zwischen den Produktfamilien Arduino und Arduino Pro ein. Es erreicht den Benutzer mit einem unten angebrachten transparenten Acrylboden, der zur (elektrischen) Absicherung dient, plus einer anschließbaren Antenne für drahtlose Kommunikation./p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="656" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/BoardVorderseiteAlsDiagrammMitTabelle-94d60c203035a126.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/BoardVorderseiteAlsDiagrammMitTabelle-94d60c203035a126.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/BoardVorderseiteAlsDiagrammMitTabelle-94d60c203035a126.png 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/BoardVorderseiteAlsDiagrammMitTabelle-94d60c203035a126.png 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Das Arduino Giga R1 WiFi Board besitzt zahlreiche Komponenten und Anschlüsse, darunter einen leistungsstarken ARM-Prozessor von ST Microelectronics mit einem M4- und einem M7-Kern/div p class="a-caption__source" (Bild:nbsp;(c) arduino.cc) /p /figcaption /figure h3 class="subheading" id="nav_unter_der_haube_1"spanUnter der Haube/span/h3 pEine wichtige Ergänzung in diesem Zusammenhang ist, dass das Board zwei 32-Bit-ARM-Kerne integriert. Der Chip von ST Microelectronics (STM32H747XI) enthält einen mit 240 MHz getakteten Cortex-M4 und einen mit 480 MHz getakteten Cortex-M7. Zu beiden Kernen kommt zusätzlich jeweils eine Floating Point Unit (FPU) mit doppelter Präzision. Der M7 verfügt über einen L1-Cache. Das Board integriert zudem eine Memory Protection Unit und Hardware zur digitalen Signalverarbeitung./p pDurch die zwei Kerne ergibt sich die Möglichkeit, zwei Programme auf unterschiedlichen Prozessoren laufen zu lassen, zum Beispiel ein rechenintensives Hauptprogramm auf dem M7 und eine Motoransteuerung oder eine Anwendung zur Erfassung von Sensorwerten auf dem M4. Als Sprachen zur Programmierung stehen primär MicroPython sowie C/C++ zur Verfügung. Für die unabdingbare Kommunikation und Synchronisation zwischen den Programmen auf M4 und M7 existiert in der zugehörigen Arduino-Bibliothek ein entsprechender RPC-Mechanismus, der Funktionsaufrufe zwischen dem M4 und dem M7 gestattet. Das Board bietet 1 MByte Arbeitsspeicher und 2 MByte Flashspeicher, der sich in zwei Bereiche für die beiden Microcontroller partitionieren lässt. Wer nur den M7 nutzt, kann die vollen 2 MByte Flashspeicher für das dort laufende Programm nutzen. Auf dem Board befinden sich des Weiteren 8 MByte SDRAM, die Entwickler mit codeSDRAM.malloc()/code allokieren, benutzen, und danach mit codeSDRAM.free()/code freigeben können (siehe Header codeSDRAM.h/code). Über einen QSPI-Anschluss sind weitere 16 MByte externer Flashspeicher angeschlossen, die Entwickler zur Datenablage verwenden können, wobei die Firmware des Giga R1 die Dateisysteme FATFS und littleFS unterstützt. Nach den hierfür erforderlichen Konfigurationsschritten ist der Flashspeicher ebenfalls als externes USB Flash Drive nutzbar./p pGrundlage des Giga ist Mbed OS, ein quelloffenes, echtzeitbasiertes, und ressourcenschonendes Betriebssystem für IoT-Boards, das sich um Aspekte wie Konnektivität, Sicherheit, Speicher, Gerätemanagement, Supportbibliotheken und Treiber kümmert. Es integriert auch RTOS, das Mechanismen für nebenläufige Threads beisteuert./p h3 class="subheading" id="nav_noch_mehr__2"Noch mehr Tiefgang/h3 pAls Eingangsspannung erlaubt Giga zwischen 6V und 24V, während die Betriebsspannung wie bei modernen Boards 3,3V beträgt. Wer also vorhandene Schaltungsentwürfe verwendet, die sich auf den Arduino Mega (oder Uno) mit seinen 5V Betriebsspannung stützen, sollte etwas Zeit für das Redesign einplanen. In diesem Fall bietet es sich an, einen Logic Level Konverter oder einen selbst gebauten Spannungsteiler zu verwenden. Jeder digitale Port bietet mit rund 8 mA relativ wenig Energie. Als kompatible Shields gibt Arduino das aktuelle Motion-Shield, das Relay-Shield, das Ethernet-Shield und das Motorsteuerungs-Shield für den Mega an./p pZur Zusammenarbeit über USB fungieren ein USB-C und ein USB-A Anschluss. Ersterer dient der Programmierung, unterstützt HID (Human Interface Design) und versorgt das Board mit Strom, sofern keine anderen Spannungsquellen angeschlossen sind, letzterer erlaubt als USB-Host die Zusammenarbeit mit Massenspeichern oder Tastaturen./p pEin dediziertes Modul (Murata LBEE5KL1DX-883) ist für die Kommunikation über WiFi (802.11b/g/n mit 65 Mbps) und Bluetooth/BLE (Versionen 5.X und 4.2) zuständig. Dem Arduino Giga R1 liegt zu diesem Zweck eine passende, über eine Micro UFL Verbindung anschließbare Antenne bei – auf dem Board selbst ist keine Antenne integriert. Über ein entsprechendes Shield lässt sich zusätzlich huckepack ein Ethernetanschluss hinzufügen. Was Bluetooth LE betrifft, nutzen Anwendungen für Version 4.2 den zugehörigen Arduino-Stack, während der Cordio-Stack die BLE Versionen 5.X unterstützt./p pFür Bus-orientierte Kommunikation mit angeschlossener Hardware stehen vier UARTs, drei I2C-Anschlüsse, zwei SPI-Ports und eine CAN-Anbindung (über einen notwendigen externen Transceiver) zur Verfügung./p pEin ATECC608A-MAHDA-T Crypto-Modul von MICROCHIP sorgt für Sicherheitsfunktionen wie Verschlüsselung und Authentifizierung./p h3 class="subheading" id="nav_ein_und__3"Ein- und Ausgänge/h3 figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="637" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/PinoutDesArduinoGiga-76417981b4e67de4.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/PinoutDesArduinoGiga-76417981b4e67de4.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/PinoutDesArduinoGiga-76417981b4e67de4.png 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/PinoutDesArduinoGiga-76417981b4e67de4.png 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Das Board besitzt eine enorme Fülle von Anschlüssen, sogar einen CAN-Bus-Anschluss, und lässt kaum Wünsche offen./div p class="a-caption__source" (Bild:nbsp;(c) arduino.cc) /p /figcaption /figure pAn Ein-/Ausgabe-Ports gibt es 76 digitale Pins, 12 analoge Ausgabepins sowie 12 PWM-fähige Pins, was für die meisten Anwendungen problemlos genügen sollte. Über Digital-Analog-Konverter lassen sich an zwei analogen Pins entsprechende Umwandlungen bewerkstelligen, was etwa bei der Audioausgabe notwendig ist. Da das Board wie üblich etliche Pins mit verschiedenen Funktionen belegt, sollte der Entwickler das natürlich beim Schaltungsentwurf berücksichtigen. Alle GPIO-Pins (Pins 22 bis 75) lassen sich Interrupt-gesteuert nutzen, was dem Programmierer hilft, schnell auf externe Ereignisse zu reagieren, etwa dem Anliegen eines Sensorwerts oder dem Betätigen eines Pushbutton./p pEin VRTC-Eingang erlaubt den kontinuierlichen Betrieb der Echtzeituhr, ein OFF-Pin das Ausschalten des Boards von außen. Es empfiehlt sich, nach Start des Boards die aktuelle Zeit über WiFi über einen NTP (Network Time Protocol)-Server zu beziehen und die Echtzeituhr damit zu füttern./p pDarüber hinaus integriert der Giga R1 Anschlüsse für Kameras (zum Beispiel Arducam über die Pins: I2C + D54-D67), Mikrofone beziehungsweise Audio (DAC0, DAC1, A7) und Anzeigen (über D1N, D0N, D1P, D0P, CKN, CKP + D68-D75) sowie einen JTAG-Konnektor für Debugging/Programmer-Hardware. Intern besitzt der Mikrocontroller einen 2D-Grafikbeschleuniger mit einer Auflösung von bis zu 1024x768 Bildpunkten./p pDamit eröffnet sich eine Fülle von Anwendungsgebieten. Als mögliche Anwendungen des Arduino Giga R1 beschreibt das a href="https://docs.arduino.cc/static/87ecbda44860150906c0415c27b9ccfc/ABX00063-datasheet.pdf" rel="external noopener" target="_blank"strongProduct Reference Manual [1]/strong/a zum Beispiel 3D-Drucker, Audioverarbeitungshardware, Geräte zur Datenakquisition, Signalverarbeitung sowie Robotikanwendungen./p pWer mehr a href="https://docs.arduino.cc/hardware/giga-r1-wifi" rel="external noopener" target="_blank"strongtechnische Details zum Giga R1 benötigt, kann entsprechende Dokumentation auf der Arduino-Seite [2]/strong/a finden./p pÜber den BOOT0-Knopf auf dem Board lässt sich durch Gedrückthalten beim Hochfahren des Boards ein OTA (Over the Air)-Firmware-Update auslösen. Mittels des RST-Buttons lassen sich Programme resetten (einfaches drücken) oder das Board in den Bootloader-Modus versetzen (zweifaches drücken kurz hintereinander), um das Board zu (re-)programmieren. Die rote LED blinkt 4 mal schnell und viermal langsam, sofern innerhalb der Mbed-OS-Firmware ein Fehler erkannt wurde./p h3 class="subheading" id="nav_ide_und__4"IDE und Programmierung/h3 pZum Entwickeln von Anwendungen eignen sich Arduino IDE 1.8.X sowie deren Nachfolger: die Arduino IDE 2.0.X. Alternativ lassen sich auch der Arduino Webeditor und die Arduino-IoT-Cloud verwenden. Eine passende Platform-IO- beziehungsweise Visual-Studio-Code-Anbindung gab es zum Zeitpunkt der Artikelerstellung noch nicht. Beim Einsatz von MicroPython bieten sich stattdessen die a href="https://thonny.org/" rel="external noopener" target="_blank"strongThonny IDE [3]/strong/a oder das a href="https://labs.arduino.cc/en/labs/micropython" rel="external noopener" target="_blank"strongArduino Lab für MicroPython [4]/strong/a an. Auf der Webseite zum Giga R1 steht allerdings der Hinweis, dass die Unterstützung von MicroPython momentan noch experimentell sei. Jedenfalls lässt sich ein MicroPython-Programm auf einem der beiden Kerne nutzen, während auf dem anderen C++-Code läuft. Freilich können auf beiden Kernen auch C++- oder MicroPython-Programme laufen./p pIch habe zum Test die Arduino IDE 2.0.5 verwendet. Über das Menü span class="tx_caps rte__tx--caps"Toolsgt;Manage Library/span installieren Nutzer die Unterstützung für Mbed OS Giga Boards v4.0.2 über den Boardmanager./p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="379" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/InstallierenGigaBoardManagerArduinoIDE-c7d30c70e6fbb5dd.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/InstallierenGigaBoardManagerArduinoIDE-c7d30c70e6fbb5dd.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/InstallierenGigaBoardManagerArduinoIDE-c7d30c70e6fbb5dd.png 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/InstallierenGigaBoardManagerArduinoIDE-c7d30c70e6fbb5dd.png 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Die Installation des Giga erfolgt in der Arduino 2.x IDE mittels des Boardmanagers/div p class="a-caption__source" (Bild:nbsp;(c) arduino.cc) /p /figcaption /figure pNach der Board-Installation können Nutzer über das span class="tx_caps rte__tx--caps"Filegt;Examples/span-Menü auf exemplarische Sketches zugreifen, entweder auf allgemeine oder spezifische für ein STM32H747_System./p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="1195" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/GigaBeispieleArduinoIDE-2367cf7a30e29487.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/GigaBeispieleArduinoIDE-2367cf7a30e29487.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/GigaBeispieleArduinoIDE-2367cf7a30e29487.png 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/GigaBeispieleArduinoIDE-2367cf7a30e29487.png 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Nach der Installation des Boards finden sich in der Arduino IDE einige Beispielssketche für das Arduino Giga R1 WiFi Board/div p class="a-caption__source" (Bild:nbsp;(c) arduino.cc) /p /figcaption /figure pDer IDE müssen wir noch mitteilen, wie sich der M4-Kern und der M7-Kern den Flashspeicher aufteilen sollen./p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="539" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/FestlegenSpeicheraufteilungArduinoIDE-ca33a68ae1ddc732.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/FestlegenSpeicheraufteilungArduinoIDE-ca33a68ae1ddc732.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/FestlegenSpeicheraufteilungArduinoIDE-ca33a68ae1ddc732.png 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/FestlegenSpeicheraufteilungArduinoIDE-ca33a68ae1ddc732.png 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"In der IDE lässt sich definieren, wie sich der M7-Kern (Hauptkern) und der M4 (Koprozessorkern) den Flashsspeicher aufteilen sollen./div p class="a-caption__source" (Bild:nbsp;(c) arduino.cc) /p /figcaption /figure pUnd außerdem, auf welchen Kern die IDE den aktuellen Sketch uploaden soll./p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="565" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/FestlegenCoreArduinoIDE-6f99781a4f9e5691.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/FestlegenCoreArduinoIDE-6f99781a4f9e5691.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/FestlegenCoreArduinoIDE-6f99781a4f9e5691.png 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/FestlegenCoreArduinoIDE-6f99781a4f9e5691.png 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Auf welchen der beiden Kerne der aktuelle Sketch landen soll, lässt sich ebenfalls über das Tools-Menü bestimmen./div p class="a-caption__source" (Bild:nbsp;(c) arduino.cc) /p /figcaption /figure pIn der Arduino IDE findet sich im Tools-Menü nach der Installation des angeschlossenen Giga-Boards die Konfiguration./p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="772" loading="eager" src="https://heise.cloudimg.io/width/638/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/KonfigGigaBoardArduinoIDE-305d1db883995578.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/KonfigGigaBoardArduinoIDE-305d1db883995578.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/KonfigGigaBoardArduinoIDE-305d1db883995578.png 1008w, https://heise.cloudimg.io/width/1276/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/KonfigGigaBoardArduinoIDE-305d1db883995578.png 2x" width="638" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Im Tools-Menü lässt sich die aktuelle Konfiguration des Boards überprüfen./div p class="a-caption__source" (Bild:nbsp;(c) arduino.cc) /p /figcaption /figure pFür die Kommunikation zwischen beiden Kernen existiert eine RPC-Bibliothek./p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="406" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/KommunikationZwischenDenKernen-acffe0093ae0e9c3.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/KommunikationZwischenDenKernen-acffe0093ae0e9c3.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/KommunikationZwischenDenKernen-acffe0093ae0e9c3.png 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/KommunikationZwischenDenKernen-acffe0093ae0e9c3.png 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Eine spezielle RPC-Bibliothek erlaubt die Kommunikation zwischen beiden Kernen./div p class="a-caption__source" (Bild:nbsp;(c) arduino.cc) /p /figcaption /figure h3 class="subheading" id="nav_programmbeispiel__5"Programmbeispiel für die Kommunikation zwischen M7 und M4/h3 pUm zwischen beiden Kernen kommunizieren zu können, bedarf es entsprechender Funktionalität zwischen den Kernen. Zu beachten sind zwei Tatsachen: Der M4 kann nicht auf den seriellen Monitor schreiben. Stattdessen nutzt der Sketch des M4 die Routine codeRPC.println()/code./p pDie RPC-Bibliothek nutzt der M4-Core zur Kommunikation mit dem M7-Core:/p a-code language="c" pre class="rte__tx--listing listing"code#include lt;RPC.hgt; // Inkludieren der RPC-Bibliothek/code/pre /a-code pInitialisierung der RPC-Bibliothek:/p a-code language="clike" pre class="rte__tx--listing listing"codevoid setup() { // Einmal ausgeführt RPC.begin(); // Initialisierung }/code/pre /a-code pDas Programm auf dem M4 sendet kontinuierlich eine Zeichenkette an den Sketch im M7:/p a-code language="c" pre class="rte__tx--listing listing"codevoid loop() { // put your main code here, to run repeatedly: RPC.println("Hello World!"); // Schreiben von Info an den M7 Core } /code/pre /a-code pIm M7-Core empfangen wir die Information und schreiben sie auf den seriellen Monitor. Hier spielt die zweite Tatsache eine Rolle: Der M4 startet nicht von selbst. Das erledigt der Aufruf von codeRPC.begin()/code im M7-Kern./p pDas Programm auf dem M7 baut eine Verbindung auf dem seriellen Monitor auf, und initialisiert die Kommunikation. Zugleich dient codeRPC.begin()/code zum Booten des M4:/p a-code language="c" pre class="rte__tx--listing listing"code#include lt;RPC.hgt; void setup() { // put your setup code here, to run once: →Serial.begin(9600); // Starten der Kommunikation // mit seriellem Monitor →RPC.begin(); // Starten der gt;Kommunikation mit M4 } /code/pre /a-code pIn der Schleife werden kontinuierlich die vom M4 empfangenen Daten gelesen:/p a-code language="c" pre class="rte__tx--listing listing"codevoid loop() { String buffer = ""; // Einlesen der Nachricht vom M4 while (RPC.available()) { buffer += (char)RPC.read(); } /code/pre /a-code pAnschließend wird die empfangene Zeichenkette auf dem seriellen Monitor geschrieben:/p a-code language="c" pre class="rte__tx--listing listing"codeif (buffer.length() gt; 0) { Serial.print(buffer); // Schreiben derselben Information // zum seriellen Monitor } } /code/pre /a-code pAuf dem seriellen Monitor sehen wir nun - wenig überraschend - die folgende Ausgabe:/p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="390" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/AusgabeAmSeriellenMonitor-979ee499eb82108f.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/AusgabeAmSeriellenMonitor-979ee499eb82108f.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/AusgabeAmSeriellenMonitor-979ee499eb82108f.png 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/AusgabeAmSeriellenMonitor-979ee499eb82108f.png 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Der M7 startet den M4 mittels RPC.begin(). wartet auf dessen Nachricht, und gibt sie am seriellen Monitor aus./div p class="a-caption__source" (Bild:nbsp;Screenshot) /p /figcaption /figure pWir können im Sketch abfragen, ob der Sketch auf dem M4 läuft:/p a-code language="c" pre class="rte__tx--listing listing"codeif (currentCPU() == "M4") { //run M4 code } /code/pre /a-code poder auf dem M7:/p a-code language="c" pre class="rte__tx--listing listing"codeif (currentCPU() == "M7") { //run M7 code }/code/pre /a-code pZum Testen des WiFi-Moduls auf dem Giga R1 WiFi habe ich einen Beispielssketch aus span class="tx_caps rte__tx--caps"Filegt;Examples/span genutzt (WiFiWebClient (c) Tom Igoe). Das Programm verbindet sich zu einem WLAN-Netzwerk, zeigt die zugehörigen Netzwerkdaten an, nimmt Verbindung zum Server codeexample.com/code auf, und holt sich die Seite codeindex.html/code, die es dann im seriellen Monitor ausgibt./p pDas folgende Beispielsprogramm ist für den Portenta H7 geschrieben, läuft aber auch auf dem Arduino Giga R1 WiFi:/p a-code language="c" pre class="rte__tx--listing listing"code/* Web client This sketch connects to a website (http://example.com) using the WiFi module. This example is written for a network using WPA encryption. For WEP or WPA, change the Wifi.begin() call accordingly. Circuit: * Arduino Portenta H7 created 13 July 2010 by dlf (Metodo2 srl) modified 31 May 2012 by Tom Igoe */ /code/pre /a-code pWir verwenden die WiFi-Bibliothek:/p pre class="rte__tx--listing"#include lt;WiFi.hgt;/pre pZum Zugriff auf das WLAN benötigen wir SSID und Passwort. Diese sollten normalerweise in einer Headerdatei wie codearduino_secrets.h/code abgelegt sein:/p a-code language="c" pre class="rte__tx--listing listing"code#include "arduino_secrets.h" ///////please enter your sensitive data in the ///////Secret tab/arduino_secrets.h char ssid[] = "#########"; // your network SSID (name) char pass[] = "#########"; // your network password // (use for WPA, or use as key for WEP) int keyIndex = 0; // your network key Index number // (needed only for WEP)/code/pre /a-code pEs soll ein Zugriff auf den Host codeexample.com/code erfolgen:/p a-code language="c" pre class="rte__tx--listing listing"codeint status = WL_IDLE_STATUS; // if you don't want to use DNS (and reduce your sketch size) // use the numeric IP instead of the name for the server: // IPAddress server(93,184,216,34); // IP address for // example.com (no DNS) char server[] = "example.com"; // host name for example.com // (using DNS) /code/pre /a-code pDer Arduino-Sketch fungiert als Web-Client:/p pre class="rte__tx--listing"WiFiClient client;/pre pZunächst etabliert der Sketch die Verbindung zum seriellen Monitor:/p a-code language="c" pre class="rte__tx--listing listing"codevoid setup() { //Initialize serial and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. // Needed for native USB port only } /code/pre /a-code p... und überprüft, ob das Board über ein WiFi-Modul verfügt:/p a-code language="c" pre class="rte__tx--listing listing"code// check for the WiFi module: if (WiFi.status() == WL_NO_SHIELD) { Serial.println("Communication with WiFi module failed!"); // don't continue while (true); } /code/pre /a-code pNun kommt es zum Verbindungsaufbau mit der angegebenen WLAN-Netzwerk-codessid/code und dem Schlüssel codepass /codeals Basis:/p a-code language="c" pre class="rte__tx--listing listing"code// attempt to connect to Wifi network: while (status != WL_CONNECTED) { Serial.print("Attempting to connect to SSID: "); Serial.println(ssid); // Connect to WPA/WPA2 network. // Change this line if using open or WEP network: status = WiFi.begin(ssid, pass); /code/pre /a-code pDrei Sekunden werden abgewartet. Im Erfolgsfall sehen wir die Ausgabe der WiFi-Client-Konfiguration:/p a-code language="c" pre class="rte__tx--listing listing"code// wait 3 seconds for connection: delay(3000); } Serial.println("Connected to wifi"); printWifiStatus(); /code/pre /a-code pAnschließend verbindet sich der Sketch mit dem gewünschten Host. Angefordert wird die Seite codeindex.html/code:/p a-code language="c" pre class="rte__tx--listing listing"codeSerial.println("\nStarting connection to server..."); // if you get a connection, report back via serial: if (client.connect(server, 80)) { Serial.println("connected to server"); // Make a HTTP request: client.println("GET /index.html HTTP/1.1"); client.print("Host: "); client.println(server); client.println("Connection: close"); client.println(); } } /code/pre /a-code pSolange Daten des Hosts anliegen, werden diese am seriellen Monitor ausgegeben:/p a-code language="c" pre class="rte__tx--listing listing"codevoid loop() { // if there are incoming bytes available // from the server, read them and print them: while (client.available()) { char c = client.read(); Serial.write(c); } /code/pre /a-code pIst die Übertragung beendet, kommt es zum Verbindungsabbau:/p a-code language="c" pre class="rte__tx--listing listing"code// if the server's disconnected, stop the client: if (!client.connected()) { Serial.println(); Serial.println("disconnecting from server."); client.stop(); /code/pre /a-code pDer Sketch endet in einer Endlosschleife:/p a-code language="c" pre class="rte__tx--listing listing"code// do nothing forevermore: while (true); } } /code/pre /a-code pDie Methode codeprintWifiStatus()/code gibt zunächst das verbundene WLAN-Netz (SSID) aus:/p a-code language="c" pre class="rte__tx--listing listing"codevoid printWifiStatus() { // print the SSID of the network you're attached to: Serial.print("SSID: "); Serial.println(WiFi.SSID()); /code/pre /a-code pDanach informiert er über die dem Board zugewiesene IP-Adresse:/p a-code language="c" pre class="rte__tx--listing listing"code// print your board's IP address: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); /code/pre /a-code pZu guter Letzt kommt es noch zur Ausgabe der Signalstärke:/p a-code language="c" pre class="rte__tx--listing listing"code// print the received signal strength: long rssi = WiFi.RSSI(); Serial.print("signal strength (RSSI):"); Serial.print(rssi); Serial.println(" dBm"); } /code/pre /a-code pDie Ausgabe des obigen Programmes schaut wie folgt aus:/p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="417" loading="eager" src="https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/WiFiBeispielsAusgabe-d6e0b8e62504a135.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/WiFiBeispielsAusgabe-d6e0b8e62504a135.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/WiFiBeispielsAusgabe-d6e0b8e62504a135.png 1008w, https://heise.cloudimg.io/width/1392/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/WiFiBeispielsAusgabe-d6e0b8e62504a135.png 2x" width="696" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Diese Ausgabe erzeugt das Beispielsprogramm nach erfolgreichem Verbindungsaufbau zum lokalen WiFi-Netzwerk und der anschließenden Kommunikation mit dem Server example.com./div /figcaption /figure h3 class="subheading" id="nav_beispiel__6"Beispiel: Sensor lesen/h3 pDas nachfolgende Beispiel arbeitet wieder mit zwei Sketches. Der erste läuft unter dem M7-Core. Die Methode codeA0Lesen()/code dient dem Auslesen des Sensorwerts am analogen Port codeA0/code. Dazu bindet und registriert der Code die Methode unter dem Namen codeA0Lesen/code als über RPC aufrufbare Methode. In codeloop()/code empfängt der M7 alle Meldungen des M4 und gibt sie anschließend auf dem seriellen Monitor aus. Wie bereits erwähnt kann Code auf dem M4 nicht auf den seriellen Monitor zugreifen, sondern muss dazu den Umweg über den M7 nutzen:/p a-code language="c" pre class="rte__tx--listing listing"code// Demo-Code für den M7-Core #include "Arduino.h" #include "RPC.h" void setup() { RPC.begin(); Serial.begin(115200); // Binden/Registrieren der Methode A0Lesen() RPC.bind("A0Lesen", A0Lesen); } void loop() { // Alles einlesen, was vom M4 kommt String buffer = ""; while (RPC.available()) { buffer += (char)RPC.read(); // Buffer auffuellen } if (buffer.length() gt; 0) { Serial.print(buffer); // und ausgeben } } /* Hier wird der aktuelle Wert vom analogen Eingang A0 gelesen und zurueckgeliefert */ int A0Lesen() { int result = analogRead(A0); return result; } /code/pre /a-code pIm M4-Core nutzen wir einen eigenen Thread codesensorThread/code, der die Methode codesensor_lesen()/code ausführt. Dieser ruft jede Sekunde die RPC-Methode codeA0Lesen()/code auf, um den aktuellen Sensorwert zu erfassen. Dann sendet er übercode RPC.println()/code eine Nachricht an den M7, die dieser am seriellen Monitor ausgibt./p pspanDemo-Code für den M4-Core:/span/p a-code language="c" pre class="rte__tx--listing listing"code#include "Arduino.h" #include "RPC.h" using namespace rtos; Thread sensorThread; void setup() { RPC.begin(); Serial.begin(115200); /* Starte neuen Thread, der die Funktion sensor_lesen ausfuehrt */ sensorThread.start(sensor_lesen); } void loop() { } // Code für den Thread void sensor_lesen() { while (true) { delay(1000); // 1 Sekunde warten // Aufruf der Funktion A0Lesen im M7 auto result = RPC.call("A0Lesen").aslt;intgt;(); RPC.println("Result is " + String(result)); } } /code/pre /a-code pAm seriellen Monitor sehen wir dann eine Ausgabe wie die folgende:/p figure class="a-inline-image a-u-inline" div img alt class="legacy-img " decoding="async" height="322" loading="eager" src="https://heise.cloudimg.io/width/300/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/SeriellerMonitorA0Lesen-7071080309fa75f1.png" srcset="https://heise.cloudimg.io/width/336/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/SeriellerMonitorA0Lesen-7071080309fa75f1.png 336w, https://heise.cloudimg.io/width/1008/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/SeriellerMonitorA0Lesen-7071080309fa75f1.png 1008w, https://heise.cloudimg.io/width/600/q70.png-lossy-70.webp-lossy-70.foil1/_www-heise-de_/imgs/18/4/0/7/4/3/5/7/SeriellerMonitorA0Lesen-7071080309fa75f1.png 2x" width="300" /div figcaption class="a-caption " p class="a-caption__text" /pdiv class="text"Der Sketch auf dem M4-Core schickt Meldungen an den M7-Core, die dieser am seriellen Monitor ausgibt./div /figcaption /figure h3 class="subheading" id="nav_alles_gut_oder__7"spanAlles gut oder was?/span/h3 pMomentan lässt die Zahl der für den Giga verfügbaren Software wie etwa Treiber und Bibliotheken noch viel Luft nach oben. Das ist allerdings der Tatsache geschuldet, dass naturgemäß in einem so frühen Stadium noch nicht viel davon existieren kann. Ein Ökosystem muss sich erst entwickeln. Der Preis erscheint etwas hoch. Dem ist allerdings entgegenzusetzen, dass sich das Giga R1 Board leistungstechnisch eher auf den Höhen der Potenta-Boards, speziell dem Portenta H7 Lite bewegt und eine hervorragende Plattform für Edge-Anwendungen wie KI bietet. Wer also lediglich ein Board für kleinere beziehungsweise weniger anspruchsvolle Problemstellungen sucht, ist mit anderen preisgünstigeren Arduino Boards, ESP32-Boards oder dem Raspberry Pi Pico W besser bedient./p pWas die Kommunikation mit der Außenwelt betrifft, lässt das Giga-Board kaum Wünsche offen. Das gilt sowohl für Kommunikation mit anderer Software via WiFi und Bluetooth als auch für die systemnahe Kommunikation mit Peripherie. Die Zahl der verfügbaren Schnittstellen ist üppig./p pDas Konzept der zwei Microcontroller und der anderen Schnittstellen entspringt der Portenta-Familie und hat deutliche Vorteile bei der Implementierung leistungshungiger Embedded Systeme. Die Positionierung des Giga R1 als Highend-Board zwischen den industriellen Arduino-Produkten und Arduino-Boards für größere Maker-Projekte ist daher sicher gerechtfertigt./p pDas soll es im Wesentlichen zu den Leitungsdetails des Arduino Giga R1 WiFi gewesen sein. In zukünftigen Folgen sprechen wir über konkrete Anwendungen. !-- RSPEAK_STOP -- !-- RSPEAK_START -- /p hr p strongURL dieses Artikels:/strongbr smallcodehttps://www.heise.de/-8039111/code/small /p p strongLinks in diesem Artikel:/strongbr smallcodestrong[1]/strongnbsp;https://docs.arduino.cc/static/87ecbda44860150906c0415c27b9ccfc/ABX00063-datasheet.pdf/code/smallbr smallcodestrong[2]/strongnbsp;https://docs.arduino.cc/hardware/giga-r1-wifi/code/smallbr smallcodestrong[3]/strongnbsp;https://thonny.org//code/smallbr smallcodestrong[4]/strongnbsp;https://labs.arduino.cc/en/labs/micropython/code/smallbr smallcodestrong[5]/strongnbsp;mailto:michael.stal@gmail.com/code/smallbr /p p class="printversion__copyright" emCopyright © 2023 Heise Medien/em /p pstronga href="https://blockads.fivefilters.org"Adblock test/a/strong a href="https://blockads.fivefilters.org/acceptable.html"(Why?)/a/p
  • 14. April 2023 um 13:13

Der Pragmatische Architekt: Blogthemen der nächsten Zeit

Von heise online
!-- RSPEAK_STOP -- figure class="aufmacherbild" img src="https://heise.cloudimg.io/width/700/q75.png-lossy-75.webp-lossy-75.foil1/_www-heise-de_/imgs/18/3/7/1/9/3/6/8/E3E06860-BCB0-4FB1-99C8-D295DC7CE6BE-f37f434962090a2f.jpeg" srcset="https://heise.cloudimg.io/width/540/q75.png-lossy-75.webp-lossy-75.foil1/_www-heise-de_/imgs/18/3/7/1/9/3/6/8/E3E06860-BCB0-4FB1-99C8-D295DC7CE6BE-f37f434962090a2f.jpeg 540w" sizes="(min-width: 80em) 43.75em, (min-width: 64em) 66.66vw, 100vw" alt class="img-responsive" figcaption class="akwa-caption" p class="caption akwa-caption__text"Das Arduino Giga R1 Board ist Theme einer baldigen Folge/p /figcaption /figure !-- RSPEAK_START -- p strongIn der nächsten Zeit bekommt dieser Blog einen Reboot. Bei den Themen gibt es eine Mischung aus Embedded Boards, Softwarearchitektur und KI. /strong /p pNach einer Pause von neun Monaten werde ich den Blog "Der Pragmatische Architekt" rebooten. Welche Themen zur Sprache kommen, beschreibt der vorliegende Beitrag./p pDieser Blog war aus zeitlichen Gründen in den letzten Monaten verwaist. Es ist an der Zeit, ihn wieder mit Leben zu füllen. In zukünftigen Folgen sollen weiterhin Embedded Boards eine wichtige Rolle spielen. Zwischendrin geht es aber auch um weitere IT-Themen wie Softwarearchitektur und KI./p pGeplant sind unter anderem Posts zu:/p ul class="rte__list rte__list--unordered"liArduino Giga R1 WiFi/liliOszilloskop Korg NTS-2 zur Analyse von Audiosignalen/liliRaspberry Pi Pico W/liliRaspberry Pi Zero (2)/lilidas unvermeidliche Thema ChatGPT/liliDirekter Zugriff auf Sensorik über PCs/li/ul pNatürlich liegt es dem Autor am Herzen, Themen zu adressieren, die Leserinnen und Leser interessieren. Gerne nehme ich zudem Anregungen in Kommentaren zu diesem Beitrag entgegen, wenn, wenn jemand ein spannendes Thema vermisst, geben Sie es gerne in den Kommentaren an. Ich freue mich jedenfalls, wieder aktiv sein zu können./p p !-- RSPEAK_STOP -- !-- RSPEAK_START -- /p hr p strongURL dieses Artikels:/strongbr smallcodehttps://www.heise.de/-7548368/code/small /p p strongLinks in diesem Artikel:/strongbr smallcodestrong[1]/strongnbsp;mailto:rme@ix.de/code/smallbr /p p class="printversion__copyright" emCopyright © 2023 Heise Medien/em /p pstronga href="https://blockads.fivefilters.org"Adblock test/a/strong a href="https://blockads.fivefilters.org/acceptable.html"(Why?)/a/p
  • 29. März 2023 um 11:22

Enterprise Java: Eclipse Foundation startet Jakarta EE Developer Survey 2023

Von heise online

(Bild: Peshkova/Shutterstock.com)

Die jährliche Befragung zu Jakarta EE läuft bis zum 25. Mai. Sie dient der Arbeitsgruppe als Richtlinie für die Weiterentwicklung der Spezifikation.

Jedes Jahr führt die Eclipse Foundation [1] beziehungsweise die Jakarta EE Working Group [2] eine große Umfrage durch, um Informationen zur Nutzung und Verbreitung von Jakarta EE zu sammeln. Diese Daten helfen der Arbeitsgruppe, die Nutzer von Jakarta EE, deren Bedürfnisse und Probleme besser verstehen zu können und sinnvolle Weiterentwicklung und Prioritäten für die Zukunft zu definieren.

Die Ergebnisse der Umfrage bleiben aber nicht nur innerhalb der Arbeitsgruppe, sondern sind als aufbereitetes PDF verfügbar [3]. Die Eclipse Foundation arbeitet die Zahlen grafisch auf. Beispielsweise zeigt folgendes Diagramm aus der letztjährigen Befragung die Beliebtheit der unterschiedlichen Application Server:

Auch 2023 gibt es wieder eine Umfrage, die bis zum 25. Mai online verfügbar ist [4]. Hierbei bitten wir jeden Entwickler und jede Entwicklerin an der Umfrage teilzunehmen, um ein möglichst diverses und breites Bild der Community zu erhalten.


URL dieses Artikels:
https://www.heise.de/-8006410

Links in diesem Artikel:
[1] https://www.eclipse.org
[2] https://jakarta.ee
[3] https://outreach.eclipse.foundation/jakarta-ee-developer-survey-2022
[4] https://www.surveymonkey.com/r/63FSHRM
[5] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 28. März 2023 um 11:59

Blog Continuous Architecture – Meine Meinung: Meetings maximieren!

Von Eberhard Wolff

(Bild: insta_photos/Shutterstock.com)

Meetings nerven! Also: abschaffen! Aber: Kommunikation ist wesentlicher Teil der Softwareentwicklung und Meetings ein wichtiges Kommunikationswerkzeug. Was nun?

Auslöser dieses Blog-Posts ist eine Twitter-Diskussion [1]. Dort ging es um die Idee, bei einem Video-Call im Hintergrund eine Anzeige zu installieren. Sie soll basierend auf dem Gehalt beziehungsweise dem Tagessatz der Beteiligten anzeigen, wie viel Geld der Video-Call kostet.

Vermutlich geht es bei der Anzeige aber nicht nur um die Kosten. Video-Calls nerven Technikerinnen und Techniker und halten sie von der wirklichen Arbeit ab. Es gibt nämlich eigentlich nur einen Indikator dafür, ob wir etwas erreicht haben: lauffähiger Code. Diesen zu entwickeln, erfordert Konzentration. Ein Video-Call kostet nicht nur Zeit, sondern unterbricht auch die Konzentration. Es dauert lange, bis man wieder produktiv am Code arbeiten kann. Die negativen Auswirkungen von Meetings auf die Produktion von lauffähigem Code sind also noch schlimmer, als es diese Anzeige nahelegen würde.

Coden ist nicht das Problem

Tatsächlich hilft die Anzeige aber nicht weiter. Schlimmer: Der Idee liegt eine falsche Wahrnehmung über Softwareentwicklung zugrunde. Nicht Code zu produzieren, ist unser größtes Problem. Das größte Problem ist es, die gemeinsame Arbeit an der Software zu koordinieren und die Anforderungen zu verstehen. Ein großes Optimierungspotential ist, Features korrekt zu implementieren und die richtigen Features zu implementieren. Kleine Unterschiede können schon massive Auswirkungen haben. Ein krasses Beispiel: Ein einziges zusätzliches Eingabefeld kann 90 % des Umsatzes kosten [2]. Es ist also kontraproduktiv, dieses Eingabefeld umzusetzen – egal wie schnell oder effizient das passiert. Der lauffähige Code mag einem zwar das Gefühl geben, dass man etwas erreicht hat, aber in Wirklichkeit war es ein Schritt in die falsche Richtung. Die beste Option wäre gewesen, diesen Code gar nicht zu schreiben. Den Code möglichst schnell und effizient zu schreiben, ist eine Scheinoptimierung.

Also doch Meetings!

Um zu verstehen, was zu entwickeln ist, muss man wohl Meetings abhalten. Schriftliche Anforderungen können nicht alle Informationen transportieren. Rückfragen, das gemeinsame Entwickeln von Ideen, Hinterfragen – das alles verlangt direkte Kommunikation und Meetings. Aber die Meetings nerven ja dennoch, und das Problem muss irgendwie angegangen werden. Die Kosten des Meetings explizit zu machen, ist naheliegend, weil es relativ einfach ist. Es ist aber die falsche Optimierungsgröße. Meetings, bei denen relevante Informationen ausgetauscht oder wichtige Entscheidungen getroffen werden, sind nützlich und nerven daher vermutlich nicht. Leider ist Nützlichkeit nicht ganz so einfach messbar, wie die Kosten. Dieses Problem des Fokus auf Kosten, weil sie leichter messbar sind, haben auch anderen Bereichen der IT, wie in einem anderen Blog-Post [3] diskutiert. Gerade weil die gemeinsame Arbeit die große Herausforderung in der Softwareentwicklung ist, sind Optimierungen an der gemeinsamen Arbeite sehr sinnvoll.

Meetings maximieren!

Also sollten wir die Qualität von Meetings verbessern. Beispielsweise kann man nach jedem Meeting die Frage stellen, wie hilfreich die Teilnehmenden das Meeting fanden. Oder man kann ein Keep / Try Feedback zur Verbesserung einholen: Was sollten man beim nächsten Meeting beibehalten (Keep)? Was kann man ausprobieren (Try)? Auch alle Meetings firmenweit schlicht abzusagen, wie Shopify dies getan hat [4], hat den Vorteil, dass vermutlich nur die Meetings wieder aufgenommen werden, die wertvoll sind. Es geht jedoch vielleicht zu weit, weil gegebenenfalls wichtige Meetings auch abgesagt werden.

So oder so ist eine Bewertung und kontinuierliche Verbesserung von Meetings ein konstruktiver Weg, um den Wert der Meetings zu maximieren. Und daher sollten wir den Wert von Meetings maximieren - und nicht etwa die Anzahl oder die Kosten.

tl;dr

Das Problem der Softwareentwicklung ist die Koordination und die Arbeit an den richtigen Herausforderungen. Dafür sind Meetings notwendig. Also sollten wir Meetings nicht einfach abschaffen, sondern den Wert maximieren.


URL dieses Artikels:
https://www.heise.de/-7549813

Links in diesem Artikel:
[1] https://twitter.com/ewolff/status/1574378678796144640
[2] https://ai.stanford.edu/~ronnyk/2009controlledExperimentsOnTheWebSurvey.pdf
[3] https://www.heise.de/blog/IT-Projekte-Kostenfaktor-statt-Wettbewerbsvorteil-6007620.html
[4] https://www.heise.de/news/Schluss-mit-Gruppenmeetings-Shopify-holt-zum-Kalender-Kahlschlag-aus-7448427.html
[5] mailto:rme@ix.de

Copyright © 2023 Heise Medien

Adblock test (Why?)

  • 18. März 2023 um 08:30
❌