Wiesbaden - Hessen nimmt die Zusammenlegung von Finanzämtern in größeren Städten in den Blick. Das Land befinde sich mitten in der Umsetzung der Strukturmaßnahmen für die Steuerverwaltung und starte «absehbar» mit der Fusion von Finanzämtern in den Großstädten, teilte eine Sprecherin des Finanzministeriums in Wiesbaden mit. Es geht dabei um die Behörden in Frankfurt, Wiesbaden, Kassel und Offenbach.
Die «Frankfurter Rundschau» hatte zuvor berichtet, dass zu einem künftigen Frankfurter «Mega-Finanzamt» - dann zusammengelegt aus den fünf bisherigen Ämtern - 1200 Dienstposten gehören sollen. In den fusionierten Behörden in Kassel wären es demnach 630, in Wiesbaden 540 und in Offenbach 400 Posten.
«Mit den Fusionen schaffen wir zukunftsfähige Strukturen für die besonderen Herausforderungen der Ballungsräume», teilte die Ministeriumssprecherin weiter mit. Dadurch könnten Doppelstrukturen abgebaut werden. Zudem ermögliche die Bündelung von Arbeitsbereichen eine weitere Spezialisierung der Teams «und damit schlussendlich eine weitere Steigerung der Durchschlagskraft im Kampf um mehr Steuergerechtigkeit und gegen Steuerkriminalität».
Die bereits seit längerem geplanten Fusionen sind Teil der laufenden Strukturreform der hessischen Steuerverwaltung. Dazu gehört etwa auch die Verlagerung von Stellen in ländliche Regionen.
Seda Basay-Yildiz, Rechtsanwältin, steht in ihrem Büro. Foto: Boris Roessler/dpa/Archivbild (Bild: dpa)
(Foto: Boris Roessler/dpa/Archivbild)
Jetzt teilen:
Jetzt teilen:
Frankfurt/Main - Auch zehn Jahre nach der Selbstenttarnung der rechtsextremen Terrorgruppe NSU sieht die Frankfurter Anwältin Seda Basay-Yildiz weiter dringenden Bedarf nach «rückhaltloser Ausklärung». Dies gelte insbesondere für die Rolle der Nachrichtendienste und möglicher Unterstützernetzwerke, sagte sie auf einer Veranstaltung des Mediendienstes Integration zu den Lehren aus dem NSU-Komplex. Im Münchner NSU-Prozess hatte Basay-Yildiz die Angehörigen von Enver Simsek vertreten, dem ersten Mordopfer des NSU.
Nach wie vor seien Akten gesperrt und Fragen offen, gerade wenn es um die Rolle eines Kontaktmanns des Verfassungsschutzes während des Mordes an Halit Yozgat in Kassel im April 2006 gehe. «Meine Mandanten sind enttäuscht und haben nach der Urteilsverkündung damit abgeschlossen, dass weitere Fragen noch geklärt werden», sagte Basay-Yildiz. Wahrscheinlich werde es nie Antworten darauf geben, wie die Tatorte ausgewählt wurden.
Frankfurter Wissenschaftler forschen zum Thema Mobilität während und nach der Coronakrise. Was die Ergebnisse für den zukünftigen öffentlichen Nahverkehr bedeuten.
Von Stefan Mannshausen
Volontär
Jetzt mit plus weiterlesen!Testen Sie jetzt unser plus Abo für nur 0,99€ im ersten Monat. Sie erhalten sofort Zugang zu allen plus Inhalten im Web und in unserer News-App.Jetzt für 0,99€ testen*Sie sind bereits Abonnent?hier einloggen
Die Fahrgastzahlen im Nahverkehr sind noch längst nicht wieder auf dem Niveau der Vor-Corona-Zeit.
(Foto: dpa)
Die Sieben-Tage-Inzidenz in Hessen steigt auf 111,6. Die aktuelle Lage hessenweit und in den Kreisen im Überblick.
Auf einer Tafel vor einem Restaurant steht ein Hinweis auf die 3-G-Regel: Gäste müssen gegen Corona geimpft, genesen oder getestet sein.
(Symbolfoto: dpa)
Jetzt teilen:
Jetzt teilen:
WIESBADEN - In Hessen ist die Sieben-Tage-Inzidenz weiter gestiegen. Die Zahl der Corona-Neuinfektionen je 100.000 Einwohner innerhalb der vergangenen sieben Tage lag nach Daten des Berliner Robert Koch-Instituts vom Freitag (Stand 8.52 Uhr) bei 111,6 nach 103,0 am Vortag. Binnen 24 Stunden wurden 1415 Neuinfektionen registriert. Weitere fünf Menschen starben im Zusammenhang mit Covid-19. Seit Beginn der Pandemie haben sich damit landesweit 353.057 Menschen infiziert, 7853 starben.
Die Hospitalisierungsinzidenz lag nach Angaben des hessischen Sozialministeriums am Freitag bei 3,73. Eine Woche zuvor betrug der Wert noch 2,27. Der Wert beschreibt, wie viele Menschen je 100.000 Einwohner in den vergangenen sieben Tagen wegen einer Infektion mit dem Coronavirus in eine Klinik aufgenommen wurden.
Auf hessischen Intensivstationen waren am Donnerstag (Stand 11 Uhr) 167 Betten mit Patienten mit einer Covid-19-Erkrankung belegt. Bei 155 sei die Infektion bestätigt gewesen, bei 12 weiteren habe der Verdacht bestanden.
CORONA-ZAHLEN FÜR DEUTSCHLAND
Die bundesweite Sieben-Tage-Inzidenz ist erneut deutlich angestiegen. Das Robert Koch-Institut (RKI) gab die Zahl der Neuinfektionen pro 100.000 Einwohner und Woche am Donnerstagmorgen mit 130,2 an. Zum Vergleich: Am Vortag hatte der Wert bei 118,0 gelegen, vor einer Woche bei 85,6. Die Gesundheitsämter in Deutschland meldeten dem RKI binnen eines Tages 28.037 Corona-Neuinfektionen. Das geht aus Zahlen hervor, die den Stand des RKI-Dashboards von 4.39 Uhr wiedergeben. Vor einer Woche hatte der Wert bei 16.077 Ansteckungen gelegen. Deutschlandweit wurden den neuen Angaben zufolge binnen 24 Stunden 114 Todesfälle verzeichnet.
Die Hospitalisierungsinzidenz und die Intensivbettenbelegung sind wichtige Indikatoren zur Beurteilung der aktuellen Corona-Lage. Überschreiten sie bestimmte Grenzen, greifen laut einem zweistufigen Konzept des Landes weitergehende Maßnahmen zur Eindämmung der Pandemie. Dies geschieht, wenn die Hospitalisierungsinzidenz über acht steigt oder die Intensivbettenbelegung über 200.
Die Corona-Zahlen für die Landkreise im Überblick
Kreis Darmstadt-Dieburg: Die Sieben-Tage-Inzidenz im Landkreis hat gegenüber dem Vortag einen Sprung um acht Prozent auf 66,1 gemacht. In der vergangenen Woche haben sich nachweislich 197 Menschen aus Darmstadt-Dieburg mit dem Corona-Virus angesteckt. Auch der hessenweite Hospitalisierungswert ist gestiegen und liegt nun bei 3,62. 48 bestätigte Corona-Fälle meldete das Gesundheitsamt Darmstadt und Darmstadt-Dieburg am Donnerstag. Damit haben sich seit Beginn der Pandemie 13 480 Darmstadt-Dieburger nachweislich angesteckt. Die Zahl der Todesfälle im Zusammenhang mit einer Corona-Infektion liegt unverändert bei 320 im Kreis. Unverändert gegenüber des Vortags ist auch die Situation an den Kreiskliniken. Am Klinik-Standort Groß-Umstadt liegen fünf Covid-Patienten auf Normalstation, die Intensivstation ist dort Covid-frei. In der Kreisklinik Jugenheim sind es weiter zehn Patienten, die auf der Intensivstation behandelt werden, teilt die Klinik am Donnerstag mit.
Kreis Groß-Gerau: Einen leichten Rückgang der Corona-Inzidenz im Kreisgebiet meldet das Robert-Koch-Institut, das die Zahl der Neuansteckungen pro 100.000 Einwohner binnen einer Woche aktuell auf 92,1 beziffert. Am Vortag lag der Wert bei 96,1. Die Zahl der mit dem Virus infizierten Personen im Kreisgebiet stieg von Donnerstag auf Freitag um 44 auf nunmehr insgesamt 17270 seit der Beginn der Pandemie im Frühjahr vergangenen Jahres. Die meisten Erkrankten gibt es aktuell in Rüsselsheim (202), gefolgt von Mörfelden-Walldorf (71) und Raunheim (45). Weitere Todesfälle im Zusammenhang mit einer Infektion waren nach Angaben des RKI im Kreisgebiet nicht zu verzeichnen.
Odenwaldkreis: Die Zahl der Corona-Fälle steigt im Odenwaldkreis deutlich an. Von Dienstag bis Donnerstag ist die Sieben-Tage-Inzidenz auf 150,9 hochgeschnellt (Stand: Donnerstag, 0 Uhr). Diesem Wert liegen 76 neue positive Testergebnisse zugrunde, mit denen die Gesamtzahl nun 5282 beträgt. Davon gelten 4891 Personen als genesen (plus 14). Auch gibt es einen weiteren Todesfall. Die betroffene Person war zwischen 80 und 89 Jahre alt und lebte im häuslichen Umfeld. Insgesamt gibt es nun 179 Todesfälle. Der Infektionssaldo liegt bei 212.
Das Gesundheitsamt erfasste in den vergangenen sieben Tagen 148 neue Corona-Infektionen. Mit 71 gab es die meisten in Erbach/Michelstadt (Erbach 17, Michelstadt 54). Wie berichtet, erklärt sich die große Fallzahlensteigerung in Michelstadt nach wie vor mit einem Ausbruch in einem Unternehmen, das in einem Stadtteil ansässig ist, und dessen Mitarbeiter teilweise in Sammelunterkünften leben. Seit Dienstag gingen von dort weitere positive PCR-Testergebnisse beim Gesundheitsamt ein. Insgesamt jedoch sei dieser Ausbruch nur bedingt verantwortlich für die Steigerung der Corona-Fälle im Kreisgebiet, berichtet das Landratsamt.
Relativ viele Neuinfektionen sind auch in der Unterzent erfasst worden. Von den 29 Fällen gab es in Höchst elf und in Breuberg sowie in Lützelbach jeweils neun. In Bad König/Brombachtal gab es 21 Fälle (Bad König: 19, Brombachtal:_zwei), im Gersprenztal 20 (Reichelsheim: zehn, Brensbach: sechs, Fränkisch-Crumbach: vier) und in Mossautal/Oberzent sieben (Mossautal: ein Fall, Oberzent: sechs). Von den 148 infizierten Personen waren 52 vollständig geimpft. Dass die Impfstoffe keinen 100-prozentigen Schutz bieten würden, war schon aus den Ergebnissen der Studien für die Zulassung ersichtlich. Ebenso wie die aktuellen praktischen Erfahrungen weisen diese allerdings auch aus, dass Geimpfte sich seltener anstecken als Ungeimpfte und vor allem ein deutlich verringertes Risiko eines schweren Krankheitsverlaufs aufweisen.
Auf der Corona-Station im Gesundheitszentrum Odenwaldkreis (GZO) in Erbach werden sechs Patienten behandelt (keiner auf der Intensivstation). Bei drei Personen davon steht das Testergebnis noch aus. In Kliniken außerhalb des Kreises befinden sich drei weitere Personen. Nach Angaben des Robert Koch-Instituts liegt die Hospitalisierungsinzidenz in Hessen bei 3,5 (Stand: Mittwoch, 0 Uhr); nach Angaben des Landes Hessen sind aktuell 162 Intensivbetten mit Corona-Patienten belegt, davon 149 Patienten mit bestätigter Infektion.
Kreis Bergstraße: Am Mittwoch vermeldete Landrat Christian Engelhardt (CDU) 97 neue Corona-Fälle. Welche Kommunen und Einrichtungen von den neu nachgewiesenen Infektionsfällen am stärksten betroffen sind, teilt der Kreis seit Anfang des Monats nicht mehr täglich mit. Erst am Freitag werden die Infektionsfälle der vergangenen sieben Tage wieder den Städten und Gemeinden zugeordnet. Auch zur Hospitalisierungsquote im Kreis machte der Landrat am Mittwoch keine Angaben.
Die Inzidenz ist derweil in den vergangenen eineinhalb Wochen ebenfalls deutlich gestiegen: Lag die Sieben-Tage-Fallzahl pro 100.000 Einwohner am 15. Oktober noch bei 37,6, beträgt der Wert nun bereits 84,1. Angesichts der aktuellen Dynamik dürfte aber auch die Bergstraße schon in den nächsten Tagen wieder den Wert von 100 überschreiten – wenngleich die Inzidenz bei der grundsätzlichen Bewertung der Lage nur noch eines von mehreren Kriterien darstellt.
Rheingau-Taunus-Kreis: Im Rheingau-Taunus-Kreis gibt es Stand 28. Oktober derzeit 25 Neuinfektionen und 185 aktive Fälle. Am Vortag waren es 165. Die Zahl der Infektionen seit Pandemiebeginn liegt bei 8.593 und die Zahl der Todesfälle seit Pandemiebeginn bei 192. Die 7-Tage-Inzidenz steht derzeit auf einem Wert von 61,4.
Wie viele Menschen in Hessen und Rheinland-Pfalz mit einer Covid-19-Erkrankung im Verlauf der Pandemie im Krankenhaus behandelt wurden und werden, zeigt diese Grafik. Klicken Sie auf die Kurven für genauere Informationen.
Der Corona-Überblick für Hessen
Immer auf dem Laufenden
Auf unseren Nachrichtenportalen halten wir Sie über die aktuellen Entwicklungen in Hessen und Deutschland auf dem Laufenden und informieren Sie, welche Auswirkungen das Coronavirus hat.
Dieser Inhalt stammt aus einer externen Quelle, der Sie aktiv zugestimmt haben. Sie können diese Cookie-Einstellung jederzeit anpassen.
Dieser Artikel wurde ursprünglich am 27.10.2021 um 13:41 Uhr publiziert.
An TypeScript kommt heutzutage kaum noch jemand vorbei, der Anwendungen für das Web und die Cloud entwickeln möchte. Tatsächlich löst TypeScript eine ganze Reihe der Probleme von JavaScript, insbesondere hinsichtlich der Skalierbarkeit im Team. Wie funktioniert TypeScript, und wie lernt man es am besten?
JavaScript polarisiert. Entweder liebt man die Sprache – oder man hasst sie. Standpunkte dazwischen sind tatsächlich eher rar. Doch egal, wie man zu der Sprache steht, gibt es eine Reihe von Problemen, wenn man JavaScript in größeren Teams und Projekten einsetzen möchte: Allzu schnell geht der Überblick verloren, und der Aufwand für Koordination und Kommunikation wachsen exponentiell. Man könnte sagen, die Entwicklung mit JavaScript skaliert nicht.
Genau hier setzt TypeScript an, eine 2012 von Microsoft erstmals veröffentlichte Sprache, die JavaScript um ein statisches Typsystem und einen Precompiler à la Babel erweitert. Der Fokus liegt dabei, wie der Name bereits nahelegt, auf dem statischen Typsystem, der Precompiler ist eher schmückendes, aber notwendiges Beiwerk.
Eine stetig zunehmende Anzahl von Teams und Projekten setzt daher auf TypeScript statt auf klassisches JavaScript, und das ist eine durchaus vernünftige Entscheidung. Allerdings stellt sich die Frage, wie der Einstieg in TypeScript am besten gelingt. Diese Frage beantwortet das Video "TypeScript lernen: Eine Einführung in 80 Minuten" des Autors, das kostenlos auf YouTube zur Verfügung steht.
Inhaltlich behandelt das Video nach einem kurzen historischen Rückblick nahezu alle Themen, die für den Alltag als Entwicklerin oder Entwickler in diesem Bereich wichtig sind. Dazu zählen unter anderem folgende Themen:
Installation und Konfiguration
Compilezeit versus Laufzeit
Typen definieren und verwenden
Typkomposition mit Unions
Generische Datentypen
Module verwenden
Klassen und objektorientierte Programmierung
Strukturelles statt nominales Typsystem
Umstieg von C#, Java & Co.
Natürlich kann ein Video von 80 Minuten nicht alle Aspekte von TypeScript bis ins letzte Detail erklären, aber ein Großteil dessen, was im Alltag von Nöten ist, wird ausführlich erläutert und an einem durchgängigen Beispiel erklärt.
In diesem Sinne – viel Spaß und Erfolg beim Einstieg in TypeScript :-)
URL dieses Artikels: https://www.heise.de/-6213601
Das Sheriffstern-Motiv auf dem Security-Booklet der 22/2021 gibt es in limitierter Auflage als 3D-Pin zum Anheften an Stoff.
Die c't-Ausgabe 20/2021 und unser Booklet "Security-Checklisten kompakt" ziert ein siebenzackiger Stern. Er symbolisiert, in welchen Bereichen unsere Security-Checklisten für mehr Sicherheit sorgen. Den Stern fanden wir so gelungen, dass wir ihm einen Auftritt in der realen Welt gönnten: Ein eigentlich auf Karnevalsorden spezialisierter Hersteller fertigte uns insgesamt 1000 Exemplare.
Die c't-Sterne haben einen Durchmesser von knapp 43 mm, sie sind aus 2 mm dickem vergoldeten Metall. Das aufgebrachte Echtgold wurde sorgfältig poliert, um dem Stern den richtigen Glanz zu verleihen. Zwei auf der Rückseite verlötete Sicherheitsknöpfe mit Federmechanismus sorgen für stabilen Halt an der Kleidung. In einem transparenten Juwelcase mit Klappdeckel und schwarzem Inlay erreichen die edlen c't-Sterne sicher geschützt ihre neuen Besitzer.
c't-Leserinnen und Leser können den Stern für 7,90 Euro ganz einfach per Mail bestellen. Wer einen (oder mehrere) haben möchte, schickt bitte eine formlose Mail mit der gewünschten Anzahl an .
Zum Konzept unserer Security-Checklisten [4] gehört, dass sie verständlich sind und leicht umzusetzen. Alle sollten von einem Grundschutz vor Hackern profitieren. Sie können uns dabei unterstützen! Reichen Sie die Checklisten gern an Freunde, Verwandte und Kollegen weiter. Die wichtigsten Handgriffe haben wir wieder im beiliegenden Mini-Booklet (PDF [5]) zusammengefasst, das sich hervorragend zum Weitergeben eignet.
Oder Sie es legen es sich einfach selbst in die Schreibtischschublade, um es bei Bedarf jederzeit griffbereit zu haben. Unter ct.de/check2022 [6] steht das neue Booklet kostenlos im PDF-Format zum Herunterladen und Weiterverschicken bereit. Dort kann auch ein begrenztes Kontingent des gedruckten Booklets [7] nachbestellt werden, zum Beispiel für Awareness-Maßnahmen in Unternehmen, Banken und Behörden.
Empfohlener redaktioneller Inhalt
Mit Ihrer Zustimmmung wird hier ein externes Video (Kaltura Inc.) geladen.
Ich bin damit einverstanden, dass mir externe Inhalte angezeigt werden.
Damit können personenbezogene Daten an Drittplattformen (Kaltura Inc.) übermittelt werden.
Mehr dazu in unserer
Datenschutzerklärung [8].
c't uplink: Der große Security-Check
URL dieses Artikels: https://www.heise.de/-6214109
Links in diesem Artikel: [1] mailto:sheriffstern@ct.de [2] https://www.heise.de/bilderstrecke/bilderstrecke_6214149.html?back=6214109;back=6214109 [3] https://www.heise.de/bilderstrecke/bilderstrecke_6214149.html?back=6214109;back=6214109 [4] https://www.heise.de/select/ct/2021/20/2119412392016740687 [5] https://ftp.heise.de/ct/listings/2021/20/ct_security_checkliste_2022.pdf [6] https://www.heise.de/ct/artikel/c-t-Security-Checklisten-2022-Schutz-fuer-alle-Faelle-6172094.html [7] https://shop.heise.de/booklet-ct-security-checkliste-2021?wt_mc=intern.shop.shop.ct2120_secbooklet.t1.textlink.textlink [8] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
Der tech:lounge Reactober ist eine Reihe von sechs Webinaren, in denen sich alles um die UI-Entwicklung mit React dreht – vom Einstieg bis zum Deep-Dive.
React ist eine leichtgewichtige UI-Technologie, mit der sich komplexe und skalierbare Web-Clients bauen lassen. Sie entwickelte sich schnell zu einer der meistgenutzten Technologien für die clientseitige Webentwicklung und enthält alle Features, die für Large-Scale-Entwicklung erforderlich sind. Mit einem funktionalen und komponentenorientierten Ansatz ist React die perfekte Plattform, um leistungsfähige Webanwendungen zu entwickeln.
Für den Einstieg in und die Vertiefung von React bietet die the native web GmbH ab dem 13. Oktober 2021 den tech:lounge Reactober [1] an, eine Reihe von insgesamt sechs jeweils vierstündigen Webinaren, in denen Grundlagenwissen und auch fortgeschrittenes Know-How vermittelt werden, was man für die zeitgemäße UI-Entwicklung auf der Basis von React benötigt.
Die Webinare werden als Livestream durchgeführt, sodass man einfach und bequem teilnehmen kann – ganz gleich ob von zu Hause oder aus dem Büro. Für Fragen steht ein Chat zur Verfügung.
Der Preis beträgt 100 Euro pro Webinar, wer drei Webinare aus einem Themenbereich als Paket bucht, erhält 20 % Rabatt gegenüber der Einzelbuchung, der Preis beträgt dann 240 Euro. Darüber hinaus gelten noch einmal günstigere Konditionen für Teams. Für Studierende und Personen in der Ausbildung beträgt der Preis gegen Nachweis 30 Euro pro Webinar. Alle Preise verstehen sich jeweils zuzüglich 19 % Umsatzsteuer.
Im Preis enthalten ist neben der Teilnahme am Livestream auch der Zugriff auf die Aufzeichnung des Webinars und die Codebeispiele.
Alle weitergehenden Informationen und eine Buchungsmöglichkeit finden sich auf der Webseite des tech:lounge Reactobers [4].
URL dieses Artikels: https://www.heise.de/-6211146
Links in diesem Artikel: [1] https://www.thenativeweb.io/techlounge/reactober [2] https://www.thenativeweb.io/techlounge/react-introduction [3] https://www.thenativeweb.io/techlounge/react-advanced [4] https://www.thenativeweb.io/techlounge/reactober
Angular oder Blazor? Eine Entscheidungshilfe für Webentwickler
ÜberKreuz Christian Liebel
Mit Blazor ist Microsoft als letzter der großen Player auf den Markt der Single-Page-App-Frameworks vorgedrungen. Dort konkurriert Blazor gegen alteingesessene Platzhirsche wie Googles Angular. Für welche Zielgruppen Angular und Blazor jeweils interessant sind, soll dieser Artikel klären.
Im März 2018 stellte Microsoft Blazor vor, ein von Steve Sanderson initiiertes Experiment, um .NET (zurück) in den Browser zu bringen: Statt auf JavaScript können Entwickler auf C# und die Templatesprache Razor zurückgreifen, um Webanwendungen zu entwickeln. Damit knüpft Blazor an das serverseitig ausgeführte ASP.NET MVC an.
Blazor ist nicht gleich Blazor
Zunächst müssen wir differenzieren zwischen den beiden Geschmacksrichtungen von Blazor: Da gibt es zunächst das serverseitig ausgeführte Blazor Server. Der Zustand der Anwendung wird hierbei vom Server verwaltet, Interaktionen der Nutzer führen zu einer Kommunikation mit dem Server über SignalR, auch HTML-Fragmente werden darüber ausgetauscht. Wenn besonders viele Nutzer die Anwendung gleichzeitig verwenden, wird der Server damit zum Bottleneck. Eine langsame Verbindung führt zu einem schlechten Antwortverhalten der Benutzeroberfläche.
Demgegenüber steht Blazor WebAssembly. Hier wird die Anwendung einschließlich der .NET-Runtime komplett clientseitig im Browser ausgeführt. Hier braucht es im einfachsten Fall lediglich einen statischen Webserver; der Browser muss die Technologie WebAssembly unterstützen. Einmal geladen kann die Anwendung auch offline ausgeführt werden. Wenn in diesem Artikel von Blazor die Rede ist, ist immer von der WebAssembly-Variante gemeint, die auch die von vornherein geplante Zielausbaustufe war. Blazor Server ist eher als eine Zwischenlösung anzusehen.
WebAssembly bringt viele Sprachen ins Web
WebAssembly (Wasm) ist ein Bytecode für das Web, der JavaScript ergänzen soll. Der große Vorteil von Wasm gegenüber dem menschenlesbaren JavaScript besteht darin, dass der Code weder geparst noch interpretiert werden muss. In anderen Sprachen geschriebener Programmcode (z.B. Rust, C#, Java) kann nach Wasm kompiliert und dann im Webbrowser ausgeführt werden.
Die Technologie soll JavaScript dabei nicht ersetzen, sondern für spezielle Anwendungsfälle ergänzen. WebAssembly-Code wird von derselben Engine ausgeführt, die auch JavaScript antreibt. Daher ist die Laufzeitperformance von Wasm-Code nicht zwingend besser als die von JavaScript-Anwendungen (siehe auch: Is WebAssembly magic performance pixie dust? [1]). WebAssembly-Code unterliegt zudem derselben Sandbox wie JavaScript. Somit können nicht beliebige native Schnittstellen aufgerufen werden, sondern nur diejenigen, für die es auch passende APIs im Web gibt.
Um Blazor-Apps im Webbrowser auszuführen, wird zunächst die .NET-Runtime in Wasm heruntergeladen und gestartet. Als nächstes wird die passende Dynamic Link Library (DLL) mit der .NET-Assembly bezogen und auf der Runtime ausgeführt (Just in Time, ab .NET 6 soll Ahead-of-Time-Kompilierung möglich werden).
WebAssembly ist standardisiert und wird von den vier großen Evergreen-Browsern Firefox, Edge, Safari und Chrome plattformübergreifend seit geraumer Zeit von Haus aus unterstützt. Damit grenzt sich Blazor auch von Silverlight ab, dem schon lange abgekündigten, proprietären und Browser-Plug-in-basierten Ansatz, .NET-Anwendungen im Browser auszuführen.
Angular: Der Platzhirsch unter den SPA-Frameworks
Angular wurde im Jahr 2016 von Google veröffentlicht. Es basiert auf den Erfahrungen von Google mit dem Vorgängerframework AngularJS, das 2009 erstmals herausgegeben wurde. Dieses wiederum entstand auf Basis der Erfahrungen bei der Implementierung großer Webanwendungen wie Google Mail. Angular ist das meistverwendetste Framework bei Google selbst.
Die ab 2016 herausgegebene Variante basiert auf der Sprache TypeScript. Vergleichbar zu Razor erweitert Angular den HTML-Sprachumfang um eine Templatingsyntax. Vor der Ausführung im Browser müssen die TypeScript-Quelldateien nach JavaScript übersetzt werden. JavaScript wiederum kann direkt im Browser ausgeführt werden, weswegen Angular-Apps deutlich „webnäher“ sind als Blazor-Anwendungen.
Während bei Angular mittlerweile jede Version eine Long-Term-Support-Version (LTS) mindestens 18 Monate Unterstützung erhält, gibt es bei Blazor noch keine solche Version. Ferner sind Community und Ökosystem bei Angular bis jetzt größer als bei Blazor.
Argumente für Blazor
Blazor ist vor allem für die Teams interessant, die über Wissen im .NET- und C#-Bereich verfügen, im Umgang mit JavaScript aber eher weniger erfahren sind und die kein Wissen in diesem Bereich aufbauen können oder wollen: Ein großer Vorteil in der Verwendung von Blazor besteht darin, dass bestehender Quelltext eventuell ins Web mitgenommen werden kann. Frühere Investitionen in eine Codebasis bleiben somit erhalten.
Wie oben angemerkt ist das aber nur dann möglich, wenn die verwendeten Funktionen und Schnittstellen im Webbrowser zur Verfügung stehen, also in JavaScript implementiert werden könnten: Ein wahlfreier Zugriff auf das Dateisystem oder Geräteschnittstellen ist auch mit WebAssembly nicht möglich. Weiterhin kann C#-Code zwischen Server und Client geteilt werden, etwa Validierungslogik. Die bekannten Komponentenhersteller bieten auch für Blazor passende Komponenten an, eventuell sind diese in bestehenden Abonnements sogar schon enthalten und können einfach mitverwendet werden.
Argumente für Angular
Angular ist deutlich älter und damit auch reifer als Blazor. Viele Features, die Angular schon seit geraumer Zeit mitbringt und dort robust funktionieren, muss Blazor erst nachliefern: Das Lazy Loading von Anwendungsbestandteilen kam bei Blazor etwa erst mit .NET 5 hinzu. Andere Features sind noch gar nicht verfügbar. Vorne liegt Angular etwa bei Ahead-of-Time-Kompilierung, was für deutlich kleinere Bundlegrößen sorgt oder bei Live beziehungsweise Hot Reloading. Hier wird die Anwendung nach einer Änderung im Quelltext automatisch neu geladen, was die Entwicklerproduktivität deutlich steigert. Beides soll in Blazor erst mit .NET 6 im November diesen Jahres nachgereicht werden. Da Angular-Anwendungen vor Ausführung im Browser nach JavaScript übersetzt werden, kommen diese Apps ohne schwergewichtige Runtime aus: Eine einfache Hallo-Welt-Anwendung ist in Angular gerade einmal 170 Kilobyte groß, bei Blazor starten Anwendungen mit 2 Megabyte Dateigröße. JavaScript-basierte Browserschnittstellen können in Angular direkt aufgerufen werden, bei Blazor braucht es hingegen ein passendes NuGet-Paket oder die Verwendung der Interop-Brücke.
Fazit
Blazor bietet sich für die Entwickler an, die über Kenntnisse oder Bestandscode im .NET-Umfeld verfügen, bei denen ein Wechsel auf einen anderen Technologiestack nicht in Frage kommt und die höhere Bundlegrößen tolerieren können. Wichtig ist dabei, dass Blazor keine magische .NET-zu-Web-Übersetzungsmaschine ist: Auch Blazor-Entwicklern bleibt die Beschäftigung mit HTML, CSS, REST-APIs, CORS oder Betriebsmodellen in der Cloud nicht erspart, Berührungspunkte mit Webtechniken wird es also definitiv geben.
Selbst für .NET-Entwickler kann das auf TypeScript aufsetzende Angular interessant sein: Mit Anders Hejlsberg zeichnet sich derselbe Sprachdesigner für TypeScript verantwortlich wie auch für C#. Beide Sprachen beeinflussen sich oft gegenseitig und sind syntaktisch sehr ähnlich. Das Framework hat sich seit Jahren im Einsatz bewährt und aufgrund des weiterverbreiteten Einsatzes bei Google selbst dürfte die Weiterentwicklung noch auf Jahre gesichert sein. Entwickler ohne .NET-Hintergrund sind bei Angular vermutlich besser aufgehoben.
Schließlich ist festzustellen, dass sich beide Ansätze funktional nicht unterscheiden: Derselbe Funktionsumfang lässt sich mit Angular wie auch in Blazor umsetzen und plattformübergreifend zur Ausführung bringen.
URL dieses Artikels: https://www.heise.de/-6197138
Links in diesem Artikel: [1] https://surma.dev/things/js-to-asc/
c't 18/2021 - Der Blick ins Heft mit E-Bike-Technik, VPN und Zauberwürfel
@ctmagazin | Blog
Ulrike Kuhlmann
In c’t 18/2021 gehts um die Technik in E-Bikes. Wir befassen uns mit dem Schutz und den Tücken von VPN, retten verschlammte Festplatten und drehen bunte Würfel.
Hallo aus Hannover,
hier bei c’t kommen etliche Leute mit dem Fahrrad zur Arbeit und bewegen sich in ihrer Freizeit gern auf zwei Rädern. Ich gehöre auch dazu und nutze das Rad außerdem als Sportgerät an Wochenenden und im Urlaub. Mein Interesse an E-Bikes ist deshalb allenfalls technischer Natur.
Unser Schwerpunkt im aktuellen Heft hat mich trotzdem angefixt, denn darin gehts genau um die Technik von E-BIkes – wir sind schließlich kein Fahrradmagazin, sondern eines für IT. Die Kollegen haben die unterschiedlichen Konzepte und Finessen aktueller E-Bikes bis hin zum Tuning unter die Lupe genommen, das finde ich total spannend. Und ich hätte nie erraten, welche E-Bike-Modelle im vergangenen Jahr besonders oft gekauft wurden: Dass elektrische Rennräder nicht so gut laufen, war klar. Aber mehr Mountainbikes mit als ohne E-Antrieb? No Way.
Rasen und Blumen ausreichend gießen und dennoch Wasser sparen? Das klappt dank smarter Ventile zwischen Wasserhahn und Gartenschlauch.
PS aus der Redaktion
Häufig finde ich in c’t Themen, mit denen ich nicht gerechnet hätte. Diesmal wars ein Artikel meines Kollegen Wilhelm Drehling: Er hat einen Rubik's Cube getestet. Ich dachte, Zauberwürfel sind längst out, von vorgestern, 1980er sozusagen. Falsch gedacht, es werden weiterhin Würfel gebaut, heute allerdings smarte Versionen. Und die sind sogar für Profis interessant. Weil ich weiß, dass meine Nichte als Kind sehr gern mit dem Zauberwürfel gespielt hat, konnte ich nicht anders: Ich hab ihr einen bestellt. Jetzt bin ich gespannt, ob sie die Variante "Der mit der App spricht" auch so gut findet, wie ich nach Lesen des c’t-Tests:
Mir war gar nicht klar, dass es sogar richtige Turniere fürs Arrangieren der bunten Würfelflächen gibt. Das muss ein irres Spektakel sein. Beherrschen Sie die Finessen des Magic Cube? Wenn ja, wie lange brauchen Sie, um die Flächen zu ordnen? Schreiben Sie mir an , ich bin gespannt!
Tabs oder Spaces? Diese Frage spaltet Entwicklerinnen und Entwickler seit Jahren, wenn nicht seit Jahrzehnten. Dabei ist die Frage, ob mit Tabs oder Spaces eingerückt werden sollte, eigentlich ganz leicht zu beantworten.
Die Frage nach der Einrückung ist annähernd so alt wie die Softwareentwicklung selbst. Für den Einsatz von Tabs und auch für den von Spaces gibt es unzählige Argumente – und jeweils mindestens genauso viele Argumente dagegen.
Eigentlich könnte man sich auf den Standpunkt stellen, dass es letztlich keine Rolle spielt, wie eingerückt wird – doch praktisch jede Entwicklerin und jeder Entwickler hat eine eigene Meinung dazu, die ausführlich begründet werden kann.
Was spricht also wirklich für den Einsatz von Tabs, was für den von Spaces – und was ist wann warum zu bevorzugen? Das folgende Video versucht, die Frage zu beantworten:
URL dieses Artikels: https://www.heise.de/-6153563
c't 17/2021 - Der Blick ins Heft mit Raspi-Projekten und Phishing-Tricks
@ctmagazin | Blog
Achim Barczok
In c't 17/2021 erfahren Sie, wie Sie mit dem Raspi alte Hardware wieder zum Laufen kriegen oder sogar ins Netz holen. Außerdem gehts um Online-Wahlwerbung, Phishing und das Homeoffice im Grünen.
Moin aus Hannover,
in den 90er Jahren habe ich einen ganzen Sommer lang geschuftet, um mir eine Stereoanlage zu kaufen: Verstärker, Radioreceiver, Decks für Kassetten und CDs – alles dabei. Nur WLAN kannte sie damals noch nicht. Und so wanderte das gute Stück irgendwann, nachdem MP3s die CD und später Streaming die MP3s ablöste, in den Keller – und einen Umzug später auf den Recyclinghof. Sollten Sie Ihre Anlage von damals noch nicht abgegeben haben, werfen Sie doch ein Blick in die aktuelle c't: Mein Kollege Dennis Schirrmacher zeigt, wie sich Spotify und andere Streamingdienste per WLAN über einen Raspi mit alten Hifi-Türmen verbinden.
Mit dem Raspi lassen sich auch noch allerlei andere alte Hardware netzfähig machen oder deren Sicherheits- und Treiberprobleme beseitigen: den alten, aber immer noch hervorragend funktionierenden Scanner zum Beispiel, oder teure Mess- oder Medizingeräte:
Es ist 2021, und immer noch schafft es weder mein Mailanbieter, noch die Software auf meinem Server, allen Spam effektiv in meinen Konten herauszufischen. Heute zum Beispiel habe ich schon einen "TESLA Model 3" gewonnen und wurde ausgewählt für die Teilnahme an einer Umfrage zur Erfahrung in Supermärkten, zu der mir der Spammer auch noch mit einem "Herzlichen Glückwunsch!" gratulierte. Mit Pflastern könnte ich in 30 Tagen 14,8 kg abnehmen und mit einem Spray meine "Standfestigkeit" erhöhen. Damit ich mir Pflaster und Spray leisten kann, könnte ich mit Amazon unverschämt viel Geld verdienen, heißt es in einer anderen Mail. Sehr verlockend – bisher hat ja nur Amazon unverschämt viel Geld an mir verdient.
Das klingt zwar amüsant, ist aber auch ziemlich nervig – und gefährlich. Immer mal wieder mischt sich darunter eine saugut gefälschte Rechnung für einen Dienst, den ich nutze, oder ein vermeintlicher Tracking-Link genau dann, wenn ich etwas bestellt habe. Ein falscher Klick trennt mich dann von einer Phishing-Attacke.
Mein Kollege Jan Mahn war nach einem Hinweis eines c't-Lesers einem dieser Phishing-Spammer auf der Spur. Er hat seinen Namen herausgefunden und bis in Telegram-Channels und Microsoft-Clouds verfolgt – und ihm dann selbst eine Phishing-Nachricht geschickt. Die ganze Geschichte lesen Sie in der aktuellen c't:
Welches waren die absurdesten – oder geschicktesten – Spam-Mails, die Sie je bekommen haben? Schreiben Sie mir an (aber forwarden Sie mir auf keinen Fall Ihren Spam ;) ).
Muss ich mich schämen, Software-Architekt zu sein?
Continuous ArchitectureEberhard Wolff
Software-Entwicklung ist voller spannender Herausforderungen, und es gibt immer etwas Neues zu lernen: Software ist schließlich eine der komplexesten Dinge, die von Menschen gebaut wird. Aber die Ergebnisse in der Realität sind manchmal mehr als enttäuschend – sie sind beschämend.
In der aktuellen c't ist ein Artikel [1], dessen Untertitel eigentlich schon der erste Aufreger sein könnte: Es geht um "typische" Datenlecks in Software für die Test- und Impfterminvergabe. Mit anderen Worten: Software in diesem Bereich ist so unsicher, dass es typische Fehler gibt – und diese Software ist auch in Produktion. Die im Artikel diskutierte Software ist medizinische Software. Nehmen wir an, wir würden über andere Medikamente sprechen. Wäre es akzeptabel, dass es "typische" vermeidbare Sicherheitsprobleme bei Medikamenten gäbe, die auch tatsächlich verordnet und eingenommen werden?
Im Übrigen ist die c’t in diesem Bereich nicht alleine. Die Gruppe zerforschung beschäftigt sich auch intensiv mit der Sicherheit solcher Lösungen und schreibt [2]: “Wir haben mittlerweile das vierte Testzentrums-Datenleck in drei Monaten gefunden und sind einfach nur noch genervt.” Was würden wir sagen, wenn es das vierte Problem in drei Monaten mit verschiedenen Medikamenten gäbe? Und Experten anschließend von der Sicherheit der Medikamente “einfach nur noch genervt” sind?
Der Vergleich zwischen Software und Medikamenten scheint auf den ersten Blick weit hergeholt zu sein. Mittlerweile ist es vielen gleichgültig, wo überall Daten leaken. Es passiert einfach so häufig, und bestimmte Unternehmen leben von dem Ausspionieren ihrer Kunden. Aber eine Schnelltest-Software [3]machte es sehr einfach Testergebnisse zu fälschen. Solche Testergebnisse werden verlangt, um Personen vor einer Ansteckung durch Kontakt mit Infizierten zu schützen. Wenn die Testergebnisse gefälscht werden können, stellt das ein Gesundheitsrisiko dar – wie ein fehlerhaftes Medikament auch. Die Luca App zur Kontaktverfolgung konnte sogar zu Angriffen auf Gesundheitsämter [4] genutzt werden. Über die Konsequenzen eines erfolgreichen Angriffs will ich nicht spekulieren.
Zeitschriften fixen Sicherheitsprobleme?
Die Einleitung des sehr lesenswerten c’t Artikels berichtet dann, dass bei der c't eine Vielzahl von Meldungen über Datenlecks bei Software für Test- und Impfterminvergabe eingegangen ist. Die c't verfolgt die Probleme und informiert die Hersteller. Hier ist der nächste Aufreger: Die c't, zerforschung und viele andere machen sicher einen super Job – aber offensichtlich muss eine Zeitschrift oder eine Gruppe von Expert:innen sich dieser Probleme annehmen. Nehmen wir als Analogie wieder Medikamente. Wäre es akzeptabel, wenn eine Zeitschrift routinemäßig über mögliche Probleme mit Medikamenten informieren würde, und diese Zeitschrift dann anschließend die Fälle näher untersucht und den Herstellern mit Rat und Tat zur Seite steht – und nur so die Probleme wirklich behoben werden? Sicher gibt es vereinzelt Medikamenten-Skandale, die über die Presse bekannt werden, und Fachzeitschrift, die wissenschaftliche Studien über Medikamente verbreiten. Aber eklatante Probleme mit Medikamenten sind eben nicht Routine. Und in der Branche und bei den Behörden sind Maßnahmen etabliert, damit das so bleibt.
Nutzer:innen sollen Sicherheit bewerten
Das Fazit ist dann der nächste Aufreger: "Ärzte und Apotheker sollten sich die Software sehr gewissenhaft ansehen (oder einen unabhängigen IT-Experten zu Rate ziehen)." Man kann kaum ernsthaft von Ärzt:innen und Apotheker:innen die Kompetenz verlangen, die Sicherheit einer Software zu bewerten. Ich arbeite im Bereich Software-Entwicklung und würde mir das selber nicht wirklich zutrauen. Vor kurzem bin ich privat um Rat in Bezug auf ein Sicherheitsthema gebeten worden und habe auch einen Rat gegeben. Allerdings bleibt das schlechte Gefühl, dass ich gegebenenfalls ein Detail übersehen habe, das am Ende dann doch große Auswirkungen hat. Daher ist der Hinweis, Expert:innen zu Rate zu ziehen, auch sehr sinnvoll. Aber auch hier bemühe ich den Vergleich zu einem Medikament: Kann man von einem Patienten verlangen, sich selber mit der Sicherheit eines Medikaments zu beschäftigen? Ich erwarte eigentlich, dass Medikamente, die ich in der Apotheke kaufe oder die mir ein Arzt verordnet, sicher sind. Üblicherweise werde ich sogar von Apotheker:innen und Ärzt:innen über die Details und mögliche Probleme proaktiv beraten.
Die Verantwortung für den Datenschutz auf die Nutzer:innen zu verlagern, kann desaströse Konsequenzen haben. Einige Lehrer:innen, die auf Eigeninitiative Videokonferenz-Lösungen in der Pandemie für ihren Unterricht genutzt haben, mussten die Sicherheit und den Datenschutz dieser Lösungen selber bewerten, weil sie oft dazu keine klaren Produktempfehlungen bekommen haben. Am Ende müssen die Lehrer:innen mit den Konsequenzen leben, wenn ihre Beurteilung falsch war – oder sie unterlassen es, sich dem Risiko auszusetzen und machen eben keinen Unterricht per Videokonferenz. Beide Konsequenzen sind nicht akzeptabel.
Aber die Empfehlung, sich die Lösungen anzuschauen, ist skurrilerweise sinnvoll: Tatsächlich können c't -Leser:innen meiner Einschätzung nach die geschilderten Herausforderungen nachvollziehen und auch Software auf diese Schwächen untersuchen. Dann sind diese Probleme aber auch für Software-Entwickler:innen nachvollziehbar – und das wirft die Frage auf, warum sie in Software überhaupt vorhanden sind. Mit anderen Worten: Wir sprechen nicht über subtile Herausforderungen, sondern solche, die man nach dem Studium einiger Seiten einer Zeitschrift verstehen kann und vermutlich auch abstellen können müsste – und daran scheitern die Hersteller dieser Software-Lösungen.
Wie unprofessionell sind wir eigentlich?
Es ist gut, dass die c’t und viele Sicherheitsforscher:innen und Expert:innen sich kümmern. Aber es ist erschreckend, dass unsere Branche der Softwareentwicklung solche fehlerhaften Produkte auf den Markt bringt. Als Ergebnis gibt es keinen Aufschrei, sondern eben einen Artikel, der davon handelt, wie Nutzer:innen sich mit der Situation arrangieren können und wie sie selber herausfinden können, ob die Software ausreichend sicher ist. Sind wir so abgestumpft, dass wir diesen Zustand akzeptieren? Ist unsere Branche wirklich so unprofessionell, dass sich Nutzer:innen eben mit diesen Mängeln unserer Produkte arrangieren müssen? Ist es unser Qualitätsanspruch, das unserer Produkte Fehler haben, die man als interessierter Laie nach dem Lesen einiger Seiten in einer Zeitschrift diagnostizieren kann?
Besonders bedenklich ist, dass diese Anwendungen personenbezogene Gesundheitsdaten verwalten. Diese Daten sind sehr sensibel und besonders schützenswert. Auch die Luca App [5] zur Kontaktverfolgung geht mit Gesundheitsdaten um, weil über die App ja gerade infizierte Personen verfolgt werden soll. Dazu muss der Infektionsstatus bekannt sein – und das sind Gesundheitsdaten. Auch für diese App gibt es sehr viel Kritik und Sicherheitslücken [6] bis hin zu den schon erwähnten möglichen Angriffen auf Gesundheitsämter. Dazu hat der Sicherheitsexperten Marcus Mengs zunächst ein Dokument mit fast 21.000 Wörtern geschrieben und dann die Arbeit an der Luca App eingestellt. Der Grund steht im Dokument [7]: “Der Hersteller gibt mir keine Zeit die Zusammenhänge zu dokumentieren, welche zu Sicherheitslücken im Code führen und patcht stattdessen ständig Code mit neuen Fehlern nach.”
Mit mindestens 25 Mio € Einnahmen [8] muss man die Luca App einen kommerziellen Erfolg nennen. Und die App hat bekanntermaßen prominente Unterstützung durch den Musiker Smudo [9]. Seine Band “Die fantastischen Vier” ist “begeistert” von dem Produkt und sieht sich als Teil des Teams [10]. Das zeigt eine Erklärungsmöglichkeit für den Zustand unserer Branche: Wenn der Applaus der Prominenz und der kommerzielle Erfolg von der Sicherheit der Anwendungen entkoppelt ist, dann ist es unlogisch, sich mit Sicherheit zu beschäftigen, weil sie für den Erfolg egal ist – außer man hat ethische Prinzipien, die dem Ignorieren entgegenstehen.
Die Spitze der Absurdität ist aber das immer wieder zu hörende Argument, dass der Datenschutz einer effektiven und effizienten IT im Wege steht. Der "Datenschutz", der in dem c’t-Artikel beschrieben wird oder der bei der Luca App “umgesetzt” wurde, kann damit zumindest nicht gemeint sein. So ist der Datenschutz auf der einen Seite nicht gewährleistet, kann aber gleichzeitig als Entschuldigung für weitere Mängel unserer Branche dienen.
Es ist ja nicht alles schlecht
Aber es gibt auch Lichtblicke. Ich war an Softwareprojekten beteiligt, die unter anderem auch personenbezogene Gesundheitsdaten verwaltet haben. Dort war sehr präsent, dass diese Daten besonders geschützt werden müssen und dementsprechend wurden diese Herausforderungen adressiert. Auch in vielen anderen Kontexten habe ich beispielsweise die Anforderungen durch die Datenschutzgrundverordnung DSGVO als wesentlich für Architektur-Diskussionen erlebt. Und natürlich gibt es für die Kontaktverfolgung-Anwendungen wie die Corona-Warn-App, die so konsequent auf Datenschutz ausgerichtet ist, dass sogar der Chaos Computer Club sie lobt [11]. Und den bereits erwähnten Sicherheitsexpert:innen und vielen anderen, die hier gar nicht erwähnt werden, ist die Situation offensichtlich nicht egal, sondern sie arbeiten aktiv daran sie zu verbessern - wofür ich mich an dieser Stelle bedanken möchte.
Am Ende bleibt aber die unangenehme Frage, ob unsere Branche im Vergleich zu anderen Branchen verantwortungsloser handelt. So oder so sollten wir uns alle anstrengen, in Zukunft Sicherheitsprobleme in Software zu vermeiden. Das ist besser, als sich zu schämen. Und das Studium des Artikels in der c't oder die Werke der Sicherheitsexpert:innen kann ein guter erster Schritt sein, um Sicherheitslücken kennenzulernen und zukünftig zu vermeiden. Vielleicht wird unsere Branche dann endlich erwachsener und verantwortungsvoller.
tl:dr
Leider ist die Qualität von Software-Lösungen oft mehr als schlecht. Sich dafür zu schämen ist aber nicht so effektiv, wie die Situation zu verbessern.
Vielen Dank an Anja Kammer, Tammo van Lessen, Tanja Maritzen, Joachim Praetorius, Max Schröter, Stefan Tilkov und Jan Seeger für die Kommentare zu einer früheren Version des Artikels.
URL dieses Artikels: https://www.heise.de/-6116235
Die Temporal API – besseres Datehandling für JavaScript
Tales from the Web sideSebastian Springer
Der ECMAScript-Standard wird stetig weiterentwickelt und JavaScript damit stetig verbessert. Eine der größten Baustellen war bisher der Umgang mit Datum und Zeit. Das ändert sich jedoch mit der neuen Temporal API.
JavaScript, Datum und Zeit, das ist so eine Geschichte für sich und sie nimmt leider kein gutes Ende. Jedes Mal, wenn ich ein neues Date-Objekt erzeuge oder noch schlimmer mit Datum und Zeit rechnen muss, frage ich mich, wie es eine Sprache mit einer so schlechten Datums- und Zeitimplementierung so weit bringen konnte. Aber seien wir mal ehrlich: Bei diesem Thema bekleckern sich auch andere Sprachen nicht mit Ruhm. Aber jetzt sprechen wir erstmal von JavaScript und einer sehr erfreulichen Entwicklung.
JavaScript erhält eine Spracherweiterung mit dem Namen Temporal, die sich mit Datum und Zeit beschäftigt und eine deutlich angenehmere Schnittstelle als die bisherige Date-API hat, die sich übrigens an einer der ersten Date-APIs von Java orientiert. Die neue Schnittstelle behebt nicht nur einige Schwächen der bisherigen, sondern gestaltet den Umgang mit Zeit und Datum deutlich moderner und greift einige Aspekte von modernen Bibliotheken wie beispielsweise die Unveränderbarkeit von Objekten auf. Aktuell befindet sich die API zwar noch als ECMAScript Proposal in der Stage 3. Das ist jedoch auch beinahe das Ende des Standardisierungsprozesses mit seinen insgesamt vier Stufen, die ein Feature durchlaufen muss, bevor es in den Standard aufgenommen wird. Üblicherweise gibt es in der dritten Stufe keine größeren Änderungen mehr an der Schnittstelle, sodass das, was wir jetzt in der Temporal API finden, mit großer Wahrscheinlichkeit auch das sein wird, was schließlich die Browserhersteller in ihre JavaScript Engines aufnehmen.
Für alle Ungeduldigen, die der Temporal API bereits jetzt eine Chance geben möchten, existiert ein Polyfill, das die Schnittstelle in aktuellen Browsern nachbildet. Das NPM-Paket mit dem Namen proposal-temporal enthält es und wird mit dem Kommando npm install proposal-temporal installiert. Die Temporal-Schnittstelle ist, wie alle nativen Sprachfeatures von JavaScript, plattformunabhängig. Das bedeutet, dass es sowohl clientseitig im Browser als auch serverseitig in Node.js zum Einsatz kommen kann. Das gleiche gilt für das Polyfill, es ist außerdem kompatibel mit allen gängigen Modulsystemen, sodass es in allen Umgebungen getestet werden kann.
Schnelleinstieg: Wie komme ich an mein Datum?
Es gibt mehrere Anwendungsfälle, denen man in JavaScript-Applikationen immer wieder begegnet und diese werden wir uns als Erstes ansehen. Beginnen wir mit dem aktuellen Zeitpunkt. Das Temporal-Objekt bietet für diesen Zweck das now-Objekt mit der plainDateTime-ISO-Methode. Gerade für den Austausch zwischen Systemen arbeiten Entwickler nicht nur mit einer Datumszeichenkette, sondern mit UNIX-Zeitstempeln, also den Sekunden, die seit dem 1.1.1970 00:00 vergangen sind. Hierfür bietet das now-Objekt die Methode instant, deren Rückgabewert die epochSeconds-Eigenschaft aufweist, die wiederum den UNIX-Zeitstempel enthält. Die letzte Aufgabe im Schnellstart mit der neuen Temporal-Schnittstelle ist das Erzeugen eines beliebigen Zeitpunkts. Dies wird über die PlainDateTime.from-Methode erreicht. Die from-Methode akzeptiert sowohl ein Konfigurationsobjekt als auch eine Zeichenkette, die das gewünschte Datum angibt. Das nachfolgende Listing zeigt die verschiedenen Szenarien.
Bestehende Applikationen werden es bei der Umstellung von der Date API auf die neue Temporal-Schnittstelle erforderlich machen, dass die Datums- und Zeitobjekte zwischen beiden Schnittstellen konvertiert werden. Listing 2 zeigt, wie eine solche Umwandlung funktionieren kann.
import { Temporal } from 'proposal-temporal';
const date = new Date('2020-12-24T20:15:32'); const temporal = new Temporal.ZonedDateTime( BigInt(date.getTime() * 10 ** 6), 'Europe/Berlin'); console.log(temporal.toString()); //2020-12-24T20:15:32+01:00[Europe/Berlin]
Dieses Codebeispiel zeigt ein grundlegendes Problem der Date API von JavaScript sehr schön: Es ist nicht möglich, ein Date-Objekt zu erzeugen, das unabhängig von einer Zeitzone ist. Das Date-Objekt hat die lokale Zeitzone der Umgebung, in meinem Fall ist das die mitteleuropäische Zeit. Die Entsprechung dieses Konzepts in Temporal sind Objekte vom Typ ZonedDateTime. In einigen Fällen ist jedoch die Information über die Zeitzone in einem Datumsobjekt gar nicht notwendig. Dieses Problem löst die Temporal-Schnittstelle, indem es verschiedene Objekte gibt, um eine Datums- und Zeit-Kombination zu repräsentieren. Die folgende Abbildung aus dem Temporal Proposal fasst diesen Sachverhalt grafisch zusammen.
Die Klassen der Temporal API
(Bild: https://tc39.es/proposal-temporal/docs/object-model.svg)
Die umfassendste Klasse der Schnittstelle ist ZonedDateTime, sie enthält die Information über den Zeitpunkt sowie die Zeitzone. Im Gegensatz dazu haben die Plain-Typen wie PlainDateTime oder PlainTime keine Information über Zeitzonen und stellen lediglich einen generischen Zeitpunkt dar. Alle Typen, außer Instant, arbeiten außerdem auf einem bestimmten Kalender. Standardmäßig nutzt Temporal den Gregorianischen Kalender, der in der ISO 8601-Norm standardisiert ist. Weitere Beispiele für Kalender, die an dieser Stelle zum Einsatz kommen können, sind der Buddhistische, der Persische oder der Japanische Kalender.
Rechnen mit Datumswerten
Ein großer Vorteil der Temporal API gegenüber der bisherigen Implementierung ist, dass sie in der Lage ist, mit Datumswerten zu rechnen und mit Zeitspannen umzugehen. Die Grundlage hierfür bildet die Duration-Klasse beziehungsweise Objekte, die der Struktur entsprechen, die diese Klasse vorgibt. Beim Rechnen mit Datumswerten kommt eine weitere Besonderheit der Temporal Schnittstelle zum Tragen: Die Schnittstelle arbeitet mit immutable Objekten, modifiziert das Ausgangsobjekt beispielsweise bei einer Addition nicht direkt, sondern gibt ein neues Objekt zurück. Wie das im Code funktioniert, zeigt folgendes Beispiel:
Alle Zoned- und Plain-Klassen der Temporal API unterstützen die add- und subtract-Methoden. Diese ermöglichen, wie die Namen schon verraten, das Hinzufügen beziehungsweise Abziehen von Zeitspannen zu einem bestimmten Zeitpunkt. Beide Methoden akzeptieren einfache JavaScript-Objekte mit den Angaben, wie viele Zeiteinheiten, also beispielsweise Monate, Tage oder Stunden, abgezogen oder addiert werden sollen. Alternativ kann auch ein Duration-Objekt eingesetzt werden.
Ein weiterer Einsatzzweck für das Duration-Objekt ist die Bestimmung der Zeitspanne, die zwischen zwei Datumswerten liegt. Soll beispielsweise herausgefunden werden, wie viele Tage zwischen dem Beginn und dem Ende der Weihnachtsferien liegen, kann der folgende Quellcode eingesetzt werden.
Sowohl der Start- als auch der Endpunkt werden durch ein PlainDate-Objekt repräsentiert, da in diesem Fall weder Zeitzone noch Uhrzeit benötigt wird. Neben der hier verwendeten until-Methode gibt es mit der since-Methode auch noch das Gegenstück, das die Zeitspanne vom Ende bis zum Start misst. Das Ergebnis ist in beiden Fällen ein Duration-Objekt, das 15 Tage umfasst. Ein solches Objekt kann dann wieder in Kombination mit weiteren Temporal-Objekten verwendet werden, um beispielsweise eine Addition oder Subtraktion durchzuführen. Die Formatierung der Ausgabe, P15D, erscheint auf den ersten Blick etwas gewöhnungsbedürftig, folgt jedoch einem klaren Format. Die Zeichenkette wird durch das Zeichen P eingeleitet, danach folgen Jahre, Monate, Wochen und Tage. Anschließend werden Datum und Uhrzeit durch das Zeichen T getrennt gefolgt von Stunden, Minuten und Sekunden.
Wären in diesem Beispiel nicht nur Datumswerte, sondern auch Uhrzeiten beteiligt, gibt es mit der round-Methode die Möglichkeit, eine Zeitspanne auf ganze Tage zu runden. Die Methode akzeptiert ein Konfigurationsobjekt, dessen wichtigste Eigenschaften largestUnit, smallestUnit und roundingMode sind. Die ersten beiden geben die kleinste beziehungsweise größte Einheit an, auf die gerundet werden soll. Mit der roundingMode-Eigenschaft können Entwickler festlegen, wie gerundet wird. Der Code in folgendem Listing rundet beispielsweise auf volle Tage ab:
Das Ergebnis der round-Methode ist wiederum ein Duration-Objekt, das die Applikation weiterverwenden kann. Das Prinzip der Immutability bleibt also auch in diesem Fall gewahrt.
Fazit
Mit der Temporal API trägt das TC39 der Tatsache Rechnung, dass die Date-Funktionalität von JavaScript einige Schwächen aufweist und für die Umsetzung moderner Applikationen nicht die beste Wahl ist. Rund um den Umgang mit Datum und Zeit sind im Laufe der Zeit eine Vielzahl von Bibliotheken entstanden. Das Temporal Proposal greift viele der Ideen auf, die diese Bibliotheken verfolgen und integriert sie in den Sprachkern von JavaScript. Das hat den Vorteil, dass diese Features, sobald die Temporal API in den Standard aufgenommen wurde, nativ vom Browser unterstützt werden. Das bedeutet, dass es keinen zusätzlichen Overhead durch Bibliotheken mehr gibt und die Funktionalität potenziell performanter ist, da sie direkt im Browser umgesetzt ist. Diese Schnittstelle ist ein sehr gutes Beispiel dafür, dass sich JavaScript stetig weiterentwickelt und dabei auf die Anforderungen der Entwickler eingeht.
paint.js.org: MS-Paint-Remake als PWA – mit Web Components und modernen Web-Capabilities
ÜberKreuz Christian Liebel
Microsoft Paint ist der Dino unter den Produktivitätsanwendungen. Das 1985 erstmals erschienene Programm brachte Kinderaugen zum Leuchten und machte viele Anwender mit der Erstellung einfacher Computergrafiken vertraut. Nun kehrt die Windows-95-Variante in Form eines webbasierten Remakes in den Browser zurück.
Ja, es stimmt. Microsoft Paint war nie zu vergleichen mit Programmen wie GIMP oder Photoshop. Keine Ebenen, in einigen Versionen nur drei Undo-Schritte, je nach Version mehr oder weniger Dateiformate. Dennoch implementiert Paint exakt den Workflow, auf den jede Produktivitätsanwendung auf dem Desktop setzt:
Dateien können vom Dateisystem geöffnet und dorthin gespeichert (neu angelegt oder überschrieben) werden.
Dateien können per Drag-and-Drop in Paint geöffnet werden.
Ein Doppelklick auf eine Bilddatei im Explorer öffnet Paint.
Zeichnungen können über die Zwischenablage mit anderen Programmen ausgetauscht werden.
Jetzt feiert Paint mit all diesen Funktionen eine Renaissance im Browser: paint.js.org [1] ist ein Remake von Microsoft Paint – als Progressive Web App (PWA), gebaut mit Web Components und unter Verwendung moderner Webschnittstellen zum Zugriff auf die Zwischenablage, das Dateisystem und die lokalen Schriftarten. Darüber hinaus unterstützt das Paint-Remake auch den Dark Mode. Das Programm lässt sich direkt im Browser ausführen und auf Wunsch auf dem Gerät installieren.
Das Paint-Remake läuft komplett ohne Installation im Browser
Einmal schreiben, überall verwenden
Als Progressive Web App [2] ist die Anwendung per se auch plattformübergreifend einsetzbar: In Chrome, Edge, Firefox und Safari, auf Android und iOS, unter Windows, Chrome OS, macOS und Linux. Die PWA ist nicht nur offline verfügbar, sondern erlaubt auch den überwiegenden Großteil der aus Microsoft Paint bekannten Aktionen: Bilddateien laden, speichern, Ausschnitte kopieren und einfügen, einfache Zeichenoperationen. Realisiert wurde das Remake mit dem Canvas-Element [3], das sich für 2-D- und 3-D-Inhalte im Web eignet. Mithilfe der im Zuge der Entwicklung von Windows 8 spezifizierten Pointer Events [4] werden Eingaben über die Maus, per Finger sowie Stift unterstützt. Auch kommen einige moderne Webschnittstellen aus dem Umfeld von Project Fugu [5] zum Einsatz.
Für einen schnelleren Zugriff kann die PWA installiert werden
Neben der Plattformunabhängigkeit ist ein weiterer Vorteil webbasierter Anwendungen, dass diese oftmals kleiner ausfallen als ihre nativen Gegenstücke. Für das Paint-Remake müssen derzeit 276 KByte übertragen werden (Brotli-komprimierter Quellcode), während die Binärdatei des Originals 340 KByte groß ist.
Web Components bilden das Rückgrat der Anwendung
Die Anwendung setzt bewusst nicht auf ein größeres Anwendungsframework, sondern benutzt die Bibliothek Lit [6]. Dabei handelt es sich um eine schlanke Bibliothek zum (einfacheren) Verfassen von Web Components [7]. Diese wiederum lassen sich zu größeren Anwendungen zusammensetzen. Als Buildtool kommt das leichtgewichtige Snowpack [8] zum Einsatz. Für die Offlineunterstützung generiert das Toolkit Workbox [9] den passenden Service Worker. Die Codebase selbst ist in TypeScript [10] implementiert.
Fugu-Schnittstellen schließen die Lücke zwischen Web und Native
Dank der File System Access API ist ein zielgenaues Speichern von Dateien möglich
Das Remake setzt eine ganze Reihe von Schnittstellen ein, die im Rahmen von Project Fugu eingeführt wurden: So etwa die Async Clipboard API [11], die asynchronen Zugriff auf die Zwischenablage erlaubt. Diese Schnittstelle unterstützen sämtliche aktuellen Browser – mit Ausnahme von Firefox. Andere Funktionen sind noch relativ neu und werden lediglich in Chromium-basierten Browsern (Chrome, Edge, Opera, Brave, Samsung Internet etc.) angeboten: Mithilfe der File System Access API [12] (generell verfügbar ab Chromium 80) können Dateien direkt vom Dateisystem geöffnet und wieder dorthin gespeichert werden. Eine einmal geöffnete Datei lässt sich direkt aus der Anwendung heraus überschreiben. Darüber hinaus lässt sich eine Datei per Drag-and-Drop ins Browserfenster ziehen. Auch dann erhält der Browser Zugriff auf das Dateihandle und kann die Datei manipulieren.
Über die Web Share API können Inhalte mit anderen Apps geteilt werden
Die "Send"-Funktion nutzt die Web Share API [13], um das gezeichnete Bild mit einer anderen installierten App zu teilen.
Auch ganz frische APIs sind dabei, die derzeit noch über about://flags gezielt vom Benutzer aktiviert werden müssen: Mit der Local Font Access API [14] kann sich Paint die komplette Liste der installierten Schriftarten abholen, sofern der Benutzer dem zustimmt. Über die File Handling API [15] kann sich eine Anwendung als Handler für eine bestimmte Dateierweiterung registrieren. Das Paint-Remake registriert sich bei Installation für die Dateierweiterung "png". Damit steht die Webanwendung für Dateien mit dieser Erweiterung über das Menü "Öffnen mit" zur Auswahl. Ist die Anwendung die einzige, die sich für eine Erweiterung registriert, übernimmt sie direkt die Rolle des Standardprogramms. Andernfalls kann der Benutzer sie als solches definieren. Dann wird die Anwendung per Doppelklick auf eine Datei mit der registrierten Dateierweiterung wieder gestartet.
Mithilfe der File Handling API hat sich Paint als Handler für PNG-Dateien hinterlegt
Soweit möglich wird in allen Fällen das Konzept des Progressive Enhancement [16] angewendet: Sollte eine API auf dem Zielsystem nicht vorhanden sein, wird eine Fallback-Schnittstelle gewählt, sofern verfügbar. Andernfalls wird die Funktion deaktiviert oder gar nicht erst angeboten.
Nur eine Nischenfunktion lässt sich im Web nicht abbilden
Die einzige Paint-Funktion, die auch in den Chromium-basierten Browsern nicht nachgebildet werden kann, ist das Festlegen der aktuellen Zeichnung als Desktophintergrund. Diese Funktion steht im Web nicht zur Verfügung. Sämtliche andere Funktionen lassen sich wie im Original oder leicht abgewandelt implementieren.
Das Paint-Remake unterstützt derzeit noch nicht alle Aktionen und Werkzeuge, die das Original mitbringt. Funktional vollständiger und besser auf unterschiedlichen Plattformen getestet ist das Remake jspaint.app [17], das jedoch nicht auf die neuen Schnittstellen zur Umsetzung von Dateisystemzugriff oder Offlinefähigkeit zurückgreift. Der Quellcode für das Paint-Remake ist auf GitHub zu finden [18].
Der Funktionsumfang des klassischen Paint war sicherlich nicht überragend. Und dennoch besitzt die Anwendung alle Eigenschaften einer typischen Produktivitätsanwendung. Das Remake zeigt, dass dank Project Fugu und zumindest auf Chromium-basierenden Browsern alle relevanten Schnittstellen für solche Anwendungen auch im Web verfügbar sind. Damit nimmt die Notwendigkeit nativer Anwendungen oder Wrapper-Ansätzen wie Electron (z.B. Slack, Visual Studio Code, Discord) zusehends ab. Das dürfte weiteren Geschäftsanwendungen, Büroprogrammen sowie Bild- und Videobearbeitungssoftware den Weg ins Web ebnen.
URL dieses Artikels: https://www.heise.de/-6058723
Als der Raspberry Pi Pico Anfang des Jahres das Licht der Welt erblickte, hat Arduino ein eigenes Board auf Basis des RP2040-Microcontrollers angekündigt. Nach wenigen Monaten ist es nun soweit. Der Arduino Nano RP2040 Connect lässt sich endlich käuflich erwerben. In diesem Beitrag geht es um erste Erfahrungen mit dem neuen Board.
Der Preis ist heiß
Das neue Board Arduino Nano RP2040 Connect
Billig ist der Nano RP2040 Connect nicht zu haben, zumal er inklusive angelöteter Pin-Leisten mit über 20 Euro zu Buche schlägt. Allerdings erscheint er gegenüber anderen Arduino Nano-Boards wie denen aus der Nano-33-Familie ausgesprochen günstig. Im Vergleich zu den RP2040-Boards von SparkFun, Adafruit oder der Raspberry Pi Foundation wartet das Arduino-Board mit vielen Extras auf, insbesondere der herbeigesehnten WiFi- und Bluetooth-Fähigkeit.
Was verbirgt sich unter der Motorhaube beziehungsweise was sind die wesentlichen Merkmale des Nano RP2040 Connect. Hier zunächst eine Übersicht mit den Eigenschaften und Ingredienzen:
Das neue Arduino Board bietet unter seiner Motorhaube einiges.
(Bild: Arduino)
Das Herzstück des Boards bildet der RP2040/Microcontroller mit seinen zwei Cortex M0+-Kernen, deren Frequenz bei 133 MHz liegt.
264 KB SRAM befinden sich auf dem RP2040-Chip, zu denen sich 16 MB (über einen QSPI-Bus verbundenes) Flash-RAM gesellen.
Um für Sicherheit zu sorgen, enthält die Hardware einen kryptografischen Koprozessor des Typs Microchip ATECC608A.
Der Buck-Stepdown-Konverter MP2322 regelt die 4.5V bis 21V Eingangsspannung auf die vom Board benötigten 3.3V herunter.
Auf dem Nano RP2040 Connect lassen sich mehrere Tiefschlafmodi einsetzen, um den Stromverbrauch zu minimieren.
Wie sein Cousin Raspberry Pi Pico enthält auch der Nano RP2040 Connect zwei PIO-Blöcke (PIO = Programmable Input/Output)mit je vier Zustandsmaschinen für programmierbare Ein- und Ausgabe, ebenso wie einen DMA-Controller und zwei Oszillatoren (PLLs) für das Antreiben von System und USB. Natürlich darf auch der interne Temperatursensor nicht in dieser Aufzählung fehlen.
Apropos USB: Das Board bietet einen USB 1.1-Controller sowie einen Micro-USB-Anschluss.
Eine SWD-Schnittstelle erlaubt Hardware-Debugging.
Größenmäßig nimmt der Nano RP2040 nur 18 x 45 mm ein, ist daher kleiner als die meisten RP2040-Boards.
Nano-Formfaktor
Die Pin-Belegung des Boards
(Bild: Arduino)
Der Formfaktor des neuen Boards entspricht dem anderer Mitglieder der Nano-Familie, angefangen vom Ur-Nano bis hin zu neueren Boards wie Arduino Nano {33 BLE Sense | 33 BLE | 33 IoT | 33 Every}. Nebst Formfaktor stimmen die Nanos auch in der Belegung ihrer Ports überein.
Das Board stellt acht analoge Ports A0…A7zur Verfügung, von denen allerdings A4 und A5 nur für I2C verwendet werden sollten. Für die Analog-Digital-Wandlung existieren 4 Kanäle mit 12 Bit Auflösung.Die Hälfte dieser Ports (d.h., alle bis aufA4…A7)unterstützt Pulsweitenmodulation (PWM). Wer A6 und A7 für die Verarbeitung analoger Signale einsetzen möchte, sollte wissen, dass diese Ports ausschließlich analoges Lesen erlauben.
Die analogen Ports lassen sich auch als digitale Ports verwenden, sodass insgesamt 22 digitale Anschlüsse zur Verfügung stehen, von denen die meisten PWM-fähig sind.
Weitere kleinere Einschränkungen:
Bei der Verwendung von A6 und A7 als digitale Ports ist nur Lesen möglich.
Der digitale Pin 3 lässt sich nicht mit INPUT_PULLUP konfigurieren.
Zum Anschluss externer Bus-Komponenten gibt es folgende Möglichkeiten:
SPI steht an den Ports D11 (CIPO, früher MOSI), D12 (COPI, früher MISO), D13 (SCK) und einem beliebigen Analog-Pin außer A6/A7 (CS; früher SS) zur Verfügung.
I2C: Wie oben bereits angedeutet, fungieren A6 und A7 als I2C-Ports SDA und SDL.
UART: Für einen UART-Anschluss gibt es analog zum Raspberry Pi Pico die Ports D0 (RX) und D1 (DX).
I2S: Das Board integriert den Bus für Audioströme.
Das Board in voller Pracht
Nach Hause telefonieren
Das Connect im Namen steht für den Chip u-blox NINA-W102, der auch schon auf anderen Arduino-Boards seine Dienste leistet und den ESP32 als Basis nutzt. Mit seiner Hilfe verfügt der Nano RP2040 Connect über WiFi und Bluetooth Low Energy 4.2. Wer die Arduino Cloud abonniert, darf sich darüber freuen, dass die Cloud bereits den Nano RP2040 Connect unterstützt.
Zum Zugriff auf WiFi-Funktionalität müssen Programmierer die entsprechende WiFiNINA-Bibliothek einbinden und in der Funktion setup() initialisieren:
In loop() befindet sich der Code für die eigentliche WiFi-Kommunikation:
void loop() { …. server = “www.heise.de“; port = 0x80; … if (client.connect(server, port)) { client.println( "GET /https://www.heise.de/suche/?q=developer HTTP/1.1"); client.println("Verbindung zu: www.heise.de"); client.println("Connection: close"); client.println(); } }
Mittels der ArduinoBLE-Bibliothek lassen sich Bluetooth-Dienste anbieten oder konsumieren.
Sensorik
Zusätzlich integriert das Nano RP2040 Connect diverse Sensoren, unter anderem eine Messeinheit zur Trägheitsmessung (ST LSM6DSOXTR ) und ein MEMS-Mikrofon (ST MP34DT06JTR):
MEMS steht für Micro ElectroMechanical Systems. MEMS-Mikrofone zeichnen sich durch niedriges Rauschen, einen weiten Dynamikbereich, geringe Verzerrung und große Resilienz gegenüber akustischer Überlast aus, weshalb sie sich sehr gut für Spracherkennung eignen. Zum Integrieren des Mikrofons gibt es die PDM-Bibliothek, die der Board Manager der Arduino IDE (siehe unten) mitinstalliert.
Die LSM6DSOXTR von ST Microelectronics implementiert sogenannte Sensor-Fusion, weil er zwei Sensoren kombiniert, einen dreidimensionalen Beschleunigungsmesser und ein dreidimensionales Gyroskop (Kreiselkompass). Hinter den drei Dimensionen verbergen sich räumliche (x,y,z)-Koordinaten, für die der Sensor Beschleunigungen und Drehmomente ermittelt.Durch seinen ML-Kern (Maschine Learning Core) kann der LSM6DSOXTR auch fortgeschrittene Funktionalität anbieten, etwa die Erkennung von freiem Fall. Wollen Entwickler diesen Sensor nutzen, müssen sie die entsprechende LSM6DSOX-Bibliothek einbinden.
Entwicklungshelfer
Das Board lässt sich in beiden Arduino IDEs programmieren, der klassischen 1.8.x-IDE und der neuen 2.0.x-IDE. Da Nano RP2040 Connect den Arduino Mbed OS Nano Boards Core [1] benutzt, genügt zur Installation die Suche nach dieser Phrase im Board Manager der jeweils eingesetzten IDE. Weitere Informationen zur Installation finden sich hier [2].
Das Board in Aktion: es blinkt mal wieder
Für alle Freunde der Online-Entwicklung: Auch der Arduino Web Editor steht für das neue Board bereit.
Das Board implementiert den gleichen Bootloader-Prozess wie der Raspberry Pi Pico, sodass sich der Arduino Nano RP2040 beim Hostsystem als USB-Massenspeicher ausgibt. Auf einem Mac erscheint das Board im Massenspeichermodus sogar als Raspberry Pi Pico. Durch ein schnelles doppeltes Betätigen der Reset-Taste lässt sich der Bootloader aktivieren, sollte einmal beim Hochladen etwas schiefgehen.
Der Nano Nano RP2040 lässt sich sowohl mit einer Arduino 1.8.x IDE als auch mit der neuen Arduino 2.x-Entwicklungsumgebung programmieren.
Für den Fall, dass das Host-Betriebssystem den Nano nicht erkennt, gibt es einen kleinen Workaround: In diesem Fall können Entwickler bei angeschlossenem Boarddas REC- und das GND-Pin mit einem Verbindungsdraht (Jumper-Wire) zusammenschließen, anschließenddie Reset-Taste betätigen, worauf sich der Arduino Nano RP2040 als USB-Speicher zu erkennen gibt, um danach einen Beispielssketch auf das Board hochzuladen.
Grundsätzlich dürften auch andere IDEs und Programmierplattformen demnächst den Arduino Nano RP2040 Connect unterstützen, darunter CircuitPython, MicroPython, Visual Studio Code und PlatformIO.
In einem Selbstversuch konnte ich zumindest validieren, dass sich der Arduino Nano RP2040 Connect mit der MicroPython-Firmware für den Raspberry Pi Pico bespielen lässt. Auch ein einfaches Programm ließ sich zum Ablauf bringen. Nähere Details folgen in zukünftigen Postings.
Angetestet: Dir MicroPython-Firmware für den Raspberry Pi Pico läuft auch auf dem Arduino
Fazit
Für detaillierte Aussagen ist es selbstverständlich noch zu früh. Trotzdem erscheint es als sicher, dass Arduino mit dem Nano RP2040 Connect ein großer Wurf gelungen ist. Das neue Board bietet das, was Anwender des Raspberry Pi Pico bislang vermisst haben: komplexere Sensoren, die Unterstützung durch das Arduino-Ökosystem, sowie vor allem WiFi- und Bluetooth-Funktionalität. Daher relativiert sich auch der etwas höhere Preis des Produktes deutlich.Vom Preis/Leistungsverhältnis her gesehen ist das neue Board sein Geld wert.
Das nur als kleiner Vorgeschmack. Zukünftige Blog-Postings widmen sich dem Newcomer detaillierter und intensiver.
URL dieses Artikels: https://www.heise.de/-6051306
Links in diesem Artikel: [1] https://github.com/arduino/ArduinoCore-mbed [2] https://docs.arduino.cc/software/ide-v1/installing-mbed-os-nano-boards [3] https://docs.arduino.cc/hardware/nano-rp2040-connect
Sleepy Pico - ein Raspberry Pi Pico geht mit C/C++ schlafen
Der Pragmatische Architekt
Michael Stal
Wer einen Microcontroller wie den RP2040 des Raspberry Pi Pico nutzt, interessiert sich früher oder später für dessen Energieverbrauch. Zum Beispiel bei einer Anwendung für mobile Messdatenerfassung oder Monitoring. Ohne Beachtung der Energiebilanz ist jede Batterie nach wenigen Stunden völlig erschöpft. Dieser Artikel erläutert deshalb, wie Entwickler höhere Energieeffizienz erreichen können.
Nimm zwei - die Schlafmodi
Laut Datenblatt gibt es beim Pico zwei mögliche Schlafmodi, den normalen zeitgesteuerten Schlafmodus (sleep mode) und den von externer Hardware abhängigen Schlafmodus (dormant mode).
Letztere Variante erfordert ein Aufwecken durch einen externen Trigger, der an einem der GPIO-Pins angeschlossen ist. Das könnte zum Beispiel ein Taster sein, ein PIR-Sensor, ein externer Taktgeber, eine NE555-Schaltung, oder ein anderer Microcontroller. Der Dormant-Modus erlaubt den geringstmöglichen Energieverbrauch, benötigt dafür aber einen externen „Wecker“. Während des Dormant-Modus sind alle internen Oszillatoren deaktiviert, ganz im Gegensatz zum Sleep-Modus.
Auf der anderen Seite ist der zeitgesteuerte Schlafmodus nicht ganz so energieeffizient, hat aber den Vorteil, dass der RP2040 in der Lage ist, sich selbst über die eingebaute Echtzeituhr RTC (Real-Time Clock) zu wecken. Der Schlafmodus hält zu diesem Zweck einen Oszillator aktiv, der die Echtzeituhr taktet.
Laut Spezifikation verbraucht der RP2040 bei 25°C im Mittel 0,8 mA im Dormant-Mode und 1.3 mA im Sleep-Mode. Das muss man im Verhältnis zum Normalverbrauch sehen. Unter Volllast können es durchaus 95 mA sein.
Gemäß der Formel P = U*I (P = Leistung, U = Spannung, I = Stromstärke) ergeben sich bei 3.3V Versorgungsspannung theoretische Werte von 313.5 mW (unter Volllast) bis zu sehr niedrigen 4.3 mW (im Sleep Mode) beziehungsweise 2.7 mW (im Dormant Mode). Nähere Informationen dazu finden sich im Datenblatt des Raspberry Pi Pico [1]. Offensichtlich bieten die beiden Schlafmodi also deutliche Einsparmöglichkeiten. Doch wie lassen sich diese Potenziale programmatisch nutzen?
All you need is code
Der frei verfügbare und unter GPLv3-Lizenz stehende Quellcode für das Beispielsprogramm dieses Beitrags ist auf GitHub abgelegt. Sie finden ihn unter diesem Link [2].
Verwendete Programmiersprachen: C und C++.
C-Beispiele aus der Spielwiese
Für MicroPython hat die Raspberry Pi Foundation leider noch keine API veröffentlicht, mit der sich der Pico über die integrierte Echtzeituhr in Tiefschlaf versetzen ließe. Anders verhält sich die Situation auf der C/C++-Seite.
Der Pico Playground [3] bietet C-Beispiele zur Veranschaulichung, die den Einsatz dieser Modi illustrieren. Alle Beispiele des Playgroundsbasieren auf den Pico-Extras [4], bei denen es sich größtenteils um noch unfertige oder unvollständig dokumentierte Bibliotheken und Beispielsanwendungen handelt. Daher sollte man neben dem Pico-Examples-Verzeichnis auch eines für Pico-Extras einrichten, um die dortigen Beispiele zu testen.
Überblick verschaffen
Wer gerne einen Einblick in die aktuellen Taktfrequenzen des Pico haben möchte, die für den Betrieb der verschiedenen Subsysteme verantwortlich sind, kann hierfür die API-Funktion frequency_count_khz() nutzen. Diese ermittelt die aktuellen Taktfrequenzen, etwa pll_usb für die Steuerung der USB-Komponenten oder den Takt des Ringoszillators, der die Echtzeituhr antreibt:
Ein erster Schritt zum reduzierten Energieverbrauch besteht darin, die System-Taktfrequenz zu reduzieren, wofür eine weitere SDK-Funktion existiert.
Der Aufruf von
set_sys_clock_khz(60000, true);
verändert die Systemfrequenz von 125 MHz auf 60 MHz. Mit Hilfe dieser Funktion ließe sich der RP2040 grundsätzlich auch übertakten, was dementsprechend zu höherem Energieverbrauch führen würde. Aber das ist eine andere Geschichte.
Hürdenlauf
Alles gut, möchte man meinen. Dummerweise legen die Schlafmodi die meisten Taktgeber schlafen. Das Programm kehrt also nach der Schlafphase nicht in den Zustand zurück, der vorher geherrscht hat. Würden Entwickler in dem Code nach Beenden des Schlafmodus eine Methode wie etwa sleep_ms() aufrufen, die zum Funktionieren einen der internen Taktgeber benötigt, bliebe das Programm an dieser Instruktion hängen. Folglich sollten Entwickler alle (benötigten) Oszillatoren nach dem Schlafmodus neu starten beziehungsweisedie zugehörigen Register wieder auf die Werte einstellen, die sie vor der Schlafphase aufwiesen.Die Programmbeispiele auf Pico-Playground lassen das notwendige Sichern der Register übrigens unerwähnt.
Um das leisten zu können, muss ein Programm die Registerwerte vor jeder Schlafphase speichern. Das lässt sich durch folgenden Code bewerkstelligen:
// save current values for clocks scb_orig = scb_hw->scr; en0_orig = clocks_hw->sleep_en0; en1_orig = clocks_hw->sleep_en1;
Für den zeitgesteuerten Schlafmodus ist die RTC (Real Time Clock) erforderlich, die mit Datum und Zeit belegt sein sollte:
Schließlich ist der Sleep-Modus von derEchtzeituhr anhängig, die für die Erweckung aus dem Tiefschlaf zu einem vorgegebenen Zeitpunkt sorgen muss.
Natürlich existieren dazu komplementäreAnweisungen für die Zeit unmittelbar nach dem Aufwachen. Diese sorgen für die Inbetriebnahme der im Schlafmodus deaktivierten Komponenten. Der Aufruf von rosc_write() reaktiviert den Ringoszillator ROSC (Ring Oscillator), der dadurch das Regime auf dem Pico wieder übernehmen kann. Dazu gleich mehr. Diegesicherten Register werden ebenfalls wieder hergestellt:
// Re-enable Ring Oscillator control rosc_write(&rosc_hw->ctrl, ROSC_CTRL_ENABLE_BITS);
Die Taktung der Echtzeituhr kann im Tiefschlaf nicht der Ringoszillatorleisten, der sich selbst schlafen legt. Stattdessen soll der Kristalloszillator XOSC das Kommando übernehmen. In Software geschieht diesüber den Aufruf von
sleep_run_from_xosc()
Es gibt, wie oben erwähnt, zwei grundsätzliche Varianten des Tiefschlafs. Im Falle des Sleep-Modus gibt der Entwickler einen Weckzeitpunkt vor. Das geschieht mittels des Aufrufs von sleep_goto_sleep_until().Beim Erreichen dieses Zeitpunkts ruft das System eine vom Programmierer zur Verfügung gestellte Callback-Funktion auf. Diese könnte wie folgt aussehen:
static void onWakeUp(void) { // put wake up actions here }
Die notwendigen Anweisungen für das Einschlafen des Raspberry Pi Pico gestalten sich also im Detail folgendermaßen.
Der Crystal Oscillator XOSC muss bekanntlich wach bleiben, weil er die Echtzeituhr antreibt.
Es muss die Festlegung eines Zeitpunkts (RTC_alarm) erfolgen, an dem die Echtzeituhr den Raspberry Pi Pico aufwecken soll.
In den Schlaf versetzen lässt sich der Microcontroller über den Aufruf von sleep_goto_sleep_until(…):
Nach dem "Wiedererwecken" ruft das System die benutzerdefinierte Rückrufroutine onWakeUp() auf.
Dormant mode
Für die zweite Schlaf-Variante, den Dormant Modus, ist der entsprechenden Pico-SDK-Funktion sleep_goto_dormant_until_edge_high() ein GPIO-Pin zu übergeben. Im Code unten ist dies der WAKEUP_PIN. Sobald der Pico an diesem Pin eine aufsteigende Signalflanke bzw. ein High-Signal erkennt, erwacht er aus seinem Tiefschlaf. Wie eingangs erläutert, könnte z.B. ein Taster oder ein PIR-Sensor der Auslöser sein:
// Go to sleep until we see a high edge on WAKEUP_PIN sleep_goto_dormant_until_edge_high(WAKEUP_PIN);
Alternativ gibt es die Methode sleep_goto_dormant_until_pin(), der man neben dem GPIO-Pin auch die boole'schen Variablen edge und active übergibt. Erstere spezifiziert, ob das Aufwachen nach einer steigenden (edge == true) oder fallenden Signalflanke (edge == false) erfolgen soll. Letztere, ob der Pin als Active HIGH (active == true) oder Active LOW (active == false) arbeitet.
Die im vorhergehenden Abschnitt gezeigten Aktionen für den Sleep mode bleiben bis auf die Aufrufe von rtc_init() und rtc_set_datetime() identisch. Auch die Rückrufmethode onWakeUp kann entfallen.
Sensoren und Aktuatoren
Es würde nur wenig nützen, wenn der Raspberry Pi Pico im Tiefschlaf weilt, die angeschlossenen Verbraucher wie Sensoren oder Aktuatoren aber viel Strom konsumieren. Eine Lösung könnte darin bestehen, die entsprechenden Komponenten über ein GPIO zu versorgen und dieses während des Tiefschlafs auf LOW zu setzen. Das hat mehrere Haken: Zum einen erlauben die GPIOs des Pico nur sehr beschränkte Stromstärken, die für viele Anwendungsfälle nicht genügen - alle GPIOs zusammen dürfen nicht mehr als 50 mA ziehen. Zum anderen benötigen einige Komponenten etwas Zeit für Start und Initialisierung beziehungsweise Kalibrierung.
Zum Glück integrieren komplexere Sensoren und Aktuatoren oft eigene Funktionalität, um sie auf Bedarfebenfalls in den Tiefschlaf zu versetzen. Wie das funktioniert, hängt natürlich von den speziellen Eigenschaften dieser Bausteine ab.
Das KiSS-Prinzip
Da die beschriebenen Aktionen immer wieder neu geschrieben werden müssen, sobald eine energieeffiziente Schaltung mit dem Raspberry Pi Pico geplant ist, liegt die Idee nahe, ein entsprechendes Mini-Framework mit der notwendigen Funktionalität zu realisieren.
Zu diesem Zweck ist die Implementierung einer C++-Klasse empfehlenswert. Diese implementiert das Singleton-Entwurfsmuster. Während der Einsatz von Singletons in vielen Fällen eher kontraproduktiv erscheint, ist es bei der Klasse Sleep ausnahmsweise sinnvoll, zumal hier wirklich nur eine zentrale Instanz vorliegen soll beziehungsweise darf. Die nachfolgend dargestellte Klasse Sleep enthält Datenelemente zum Speichern und Restaurieren der Oszillator-Register vor beziehungsweise nach dem Schlafen, zudem die für den Dormant-Modus benötigte Information bezüglich des GPIO-Pins, an dem der Pico im Dormant-mode ein Weck-Signal registrieren soll, um seinen Tiefschlaf zu unterbrechen. An diesem GPIO-Eingang (wakeup_pin) lassen sich unterschiedliche Signalquellen anschließen.
Für die durch die RTC gesteuerte Schlafenszeit (Sleep-mode) benötigt die Klasse Information über Anfangs- und Alarmzeitpunkt (_init_time, _alarm_time).
Die globale Singleton-Instanz lässt sich entsprechend über die Methoden XXXconfigure() konfigurieren oder rekonfigurieren:
Dabei legt der Aufrufer den Modus durch die aufgerufene Konfigurationsmethode fest (configureDormant(), configureSleep(), configureNormal), unter dem die Anwendung ablaufen soll. Das entspricht den beschriebenen Schlafmodi, wobei Normal den Ablauf ohne Schlafenszeiten realisiert. Das ist zum Beispiel bei der Fehlersuche nützlich oder bei der Verbrauchsmessung der unterschiedlichen Modi. Die Methoden before_sleep(), start_sleep() und after_sleep() kapseln die weiter oben erläuterte Funktionalität zum Vorbereiten des Schlafs, Durchführen des Schlafs und Wiederaufsetzen nach der Schlafphase:
class Sleep { public: enumMODE { NORMAL = 1, SLEEP = 2, DORMANT = 4 }; // class implemented using the // Singleton design pattern. static Sleep& instance() { static Sleep _instance; return _instance; }
// No copy constructor or assignment operator = Sleep(Sleep const&) = delete; void operator=(Sleep const&)= delete;
// used to (re-)configure void configureDormant(void (*setupfnc)(), void (*loopfnc)(), uint8_t WAKEUP_PIN, bool edge, bool active); ... // get current mode MODE get_mode();
// display current frequencies void measure_freqs();
// saves clock registers // and initializes RTC for sleep mode void before_sleep();
// function responsible for sleep // sleep ends with high edge (DORMANT) or when alarm time is reached (SLEEP) void start_sleep();
// sleep recovery void after_sleep();
// kind of run shell: calls _setup once, and // implements infinite loop where sleep phases // are initiated and _loop is being called // in each iteration. // Actually, this function implements an // event loop: void run();
private: uint _scb_orig; // clock registers saved before DORMANT or SLEEP mode uint _en0_orig; // "" uint _en1_orig;// "" MODE _mode;// can be SLEEP, DORMANT or NORMAL
uint _wakeup_pin;bool _edge; bool _active; datetime_t _init_time;// initial time set datetime_t _alarm_time; // alarm time void (* _setup)();// user-defined setup function - called once void (* _loop) (); // user-defined loop function: called in each // iteration Sleep(){}; // private constructor };
Ablauf nach Arduino-Art
Einige haben sich wahrscheinlich über die Funktionszeiger _setup und _loop am Ende der Klassendefinition gewundert, die auf benutzerdefinierte Funktionen verweisen.
Wie bei der Arduino-Entwicklung erwartet die Klasse Sleep einen Zeiger auf eine setup()-Funktion und einen auf eine loop()-Funktion.
Die Methode run() ruft zunächst die konfigurierte setup-Funktion auf, die Code für die Initialisierung von Komponenten, benötigte Deklarationen und weitere Teile enthalten kann, welche zu Start der Anwendung einmalig ablaufen sollen.
Danach startet eine Endlosschleife, die in jeder Schleifeni-Ieration zunächst die Methoden before_sleep(), start_sleep(), after_sleep() aufruft, um den gewünschten Schlafmodus, sleep oder dormant, implementieren. Nach jeder Schlafphase führt run() die benutzerdefinierte Methode loop() aus, in der sich zum BeispielMessungen vornehmen, Daten verarbeiten, oder Geräte ansteuern lassen. Hier passiert also die eigentliche Routinearbeit:
void Sleep::run() { _setup(); // called once while(true) { if (_mode != MODE::NORMAL) { before_sleep(); start_sleep(); after_sleep(); // calls _loop in each iteration } else { _loop(); // NORMAL mode => // must explicitly call _loop } } }
Das war alles sehr theoretisch. Den Einsatz in der Praxis soll ein konkretes Anwendungsbeispiel illustrieren.
Anwendungsszenario: Wetterdatenerfassung mit dem BME280 und einem OLED-Display
Eine typische Problemstellung ist das Erfassen von Sensorwerten, etwa bei der Messung von Wetter- oder Umweltdaten. Diese findet normalerweise in längeren zeitlichen Abständen statt. Während dieser untätigen Warteperioden lässt sich der RP2040 in den Schlaf versetzen, um die Batterielaufzeit zu verlängern. Als allseits beliebtes Beispiel soll also wieder einmal eine Wetterstation fungieren, die folgende Schaltung realisiert:
Prototypischer Aufbau der Wetterstation auf einem Steckbrett
Als Sensor nutzt die Schaltung den bekannten BME280 von Bosch, der sich über SPI (Serial Peripheral Interface) anschließen lässt. Dieser Sensor misst Temperatur, Luftfeuchtigkeit und Luftdruck, woraus sich per barometrischer Formel die ungefähre Höhe berechnen lässt. Das Datenblatt des Sensors [5] findet sich auf der Webseite von Bosch-Sensortec.
Breakout-Board mit dem BME280 von Bosch-Sensortec
Ein BME280 benötigt zwischen 1.8V und 3.6V Eingangsspannung. Er verbraucht im Schlafmodus in der Regel 0.1 uA (maximal 0.3 uA), während einer Messung 340 uA (Feuchtigkeit), 350 uA (Temperatur) und 740 uA (Druck).
Für die Programmierung der Schaltung kommt Code von der Raspberry-Pi-Organisation zum Einsatz. Die C-Routinen hat der Autor in eine C++-Wrapperklasse BME280 eingebettet, Fehlerkorrekturen vorgenommen, und weitere Funktionalität hinzugefügt. So etwa die Berechnung der Höhe und die Implementierung des sogenannten Forced Mode, bei dem der Sensor nur dann aktiv ist, sobald eine Messung erfolgt. Dadurch lässt sich sein Stromhunger auf ein Minimum reduzieren.
Zur Ausgabe der Messwerte dient ein über I2C angeschlossenes monochromes OLED-Display des Typs SSD1306 (siehe Datenblatt [6]) mit einer Auflösung von 128 x 64 Pixeln. Die Eingangsspannung sollte zwischen 1.65 V und 3.3 V betragen. Während des Schlafs verbraucht die Anzeige etwa 10 uA. Im Betrieb können es hingegen durchschnittlich zwischen 50 uA und 430 uA sein.
Das preisgünstige SSD1306-Display bietet 128 x 64 Pixel
Als Treiber nutzt das Beispiel eine Bibliothek von Larry Bank.
Zur Stromreduktion gibt es die Möglichkeit, die Anzeige programmatisch ein- und auszuschalten. Dadurch lassen sich die aktiven Zeiten des Displays und damit dessen Stromverbrauch begrenzen.
Ein mit GPIO-Pin 15 (WAKEUP_PIN) und derVersorgungsspannung verbundener Taster dient im Dormant Mode des Raspberry Pi Pico als externer Trigger. Drückt man ihn, erwacht der Pico, führt eine Messung durch, deren Messwerte am OLED-Display für ein paar Sekunden erscheinen, worauf das Ausschalten der Anzeige erfolgt. Den Beginn der Messung zeigt die eingebaute LED an, die zu diesem Zweck kurz blinkt.
Zur Stromversorgung nutzt der Autor einen Batteriehalter für eine Batterie des Typs 18650. Grundsätzlich wäre natürlich jedes andere Setup möglich, etwa der Einsatz von LiPos oder die Verwendung einer Solarzelle.
Bill of Materials (Beispiel)
Für die Schaltung sind folgende Komponenten notwendig, die insgesamt für unter 20 Euro zu haben sind.Die Preise für Batteriehalter plus Batterie oder ein LiPo sind ebenso wie das USB-Kabel zum Programmieren des Raspberry Pi Pico nicht eingerechnet.
SDSD1306 ca. 5,00 Euro
BME280 (SPI) ca. 4,60 Euro
Raspberry Pi Pico ca. 4,10 Euro
Breadboard ca. 3,00 Euro
Dupontkabel, Taster ca. 1,00 Euro
GESAMT: ca. 19,70 Euro
Das Anwendungsprogramm
Gleich vorab. Der gesamte Code liegt auf Github (siehe die GitHub-Seite [7]) bereit, um Tipparbeit zu sparen und damit Energieverbrauch zu reduzieren.
Die Funktion setup() enthält den notwendigen Code für die Initialisierung von Sensor und Anzeige. Zudem nutzt die Software die eingebaute LED an GPIO25, um Beginn und Ende einer Sensormessung zu signalisieren. Aufgabe der Funktion welcome() ist einzig die Ausgabe einesStart-Bildschirms:
void setup() { gpio_init(LED_PIN); // Use built-in LED to signal wake time gpio_set_dir(LED_PIN, GPIO_OUT);
// ssd1306 OLED is initialized oled_rc = myOled.init(); myOled.set_back_buffer(ucBuffer); myOled.fill(0,1);
// Welcome screen welcome(myOled);
// empty read as a warm-up myBME280.measure(); sleep_ms(100); }
In der Funktion loop() findet die Messung und die Ausgabe der Messergebnisse am SSD1306 statt:
void loop() { // get measurement from BME280 gpio_put(LED_PIN, 1); result = myBME280.measure(); gpio_put(LED_PIN, 0); draw_on_oled(myOled, result); }
Aufgabe des Hauptprogrammes (main()) ist im wesentlichen das Konfigurieren der Sleep-Instanz, unter anderem mit Zeigern auf die setup()- & loop()-Funktionen sowie der im Dormant-Modus benötigten Angabe des gewünschten GPIO-Eingangs.Zusätzlich reduziert main() gleich zu Beginn die Systemfrequenz des Pico von 125 MHz auf 60 MHz, um den Energieverbrauch zu minimieren. Die Wetterstation soll beim Betätigen eines Pushbuttons die Messung starten und deren Ergebnisse anzeigen, weshalb der extern getriggerte Dormant-Modus zum Einsatz kommt.Am Schluss geschieht der Aufruf der run()-Methode, die den gesamten Rest der Verarbeitung steuert.
int main() { stdio_init_all(); sleep_ms(3000); // required by some OSses to make Pico visible
// Change frequency of Pico to a lower value printf("Changing system clock to lower frequency: %d KHz\n", SYSTEM_FREQUENCY_KHZ); set_sys_clock_khz(SYSTEM_FREQUENCY_KHZ, true);
// configure Sleep instance // using Dormant mode // pointers to loop() and setup() functions // start and end of alarm period // WAKEUP_PIN where high edges are detected Sleep::instance().configureDormant(&setup, &loop, WAKEUP_PIN, true, true); // show clock frequencies Sleep::instance().measure_freqs(); // start event loop Sleep::instance().run(); return 0; }
Mit der Sleep-Klasse lässt sich eine ganze Menge infrastrukturellen Codes einsparen, weshalb Entwickler sich auf die eigentliche fachliche Logik konzentrieren können.
Leider funktionieren die Schlafmodi nicht immer problemlos:
Nach dem Schlaf ist keine Ausgabe per printf() oder puts() am seriellen Monitor mehr möglich. Zum Debuggen sollten Maker daher die Picoprobe als Hardware-Debugger einsetzen.
Es kann passieren, dass der Pico im Schlafmodus „einfriert“.
Das mag an Fehlern in der Pico-SDK oder an der unzureichenden Dokumentation dieser Betriebsarten liegen. Als einfache, aber schmutzige Abhilfe ist es vorläufig ratsam, einen zusätzlichen Taster zwischen RUN-Eingang und einem der GND-Ausgänge des Raspberry Pi Pico anzubringen, um den Microcontroller im Falle des Falles reset-ten zu können. Sobald es weitere sachdienliche Hinweise geben sollte, wie diese Problemzonen zu umschiffen sind, erweitert und ändert der Autor den bereitgestellten Code.
Verbrauchsmessungen
Um den tatsächlichen Stromverbrauch einer Schaltung messen, bietet sich die Serienschaltung eines Multimeters oder Amperemeters zwischen Stromversorgung und Pico an. Einige Labornetzteile ermöglichen ebenfalls die Messung der von dem Verbraucher benötigten Leistung. Leider eignen sich nicht alle Messgeräte für die Erfassung von extrem niedrigen Stromstärken und Verbrauchswerten. Für genaue Aussagen lohnt sich daher der Erwerb eines uCurrent-Boards [9], das sich für Messungen von Strömen in uA-Bereich eignet.
Fazit
Um einen Raspberry Pi Pico für eigene Anwendungen, speziell solche mit Batteriebetrieb, energieeffizient zu nutzen, gibt es zwei Schlaf-Modi. Während der Dormant-Mode für das Aufwachen auf eine externe Quelle angewiesen ist, kann sich der RP2040 im Sleep-Mode selbst über die Echtzeituhr wiedererwecken. Dabei ist allerdings darauf zu achten, dass die Anwendung nach dem Wecken alle Oszillatoren wieder auf ihre ursprünglichen Frequenzen einstellt. Der alleinige Fokus auf den Pico reicht in realen Anwendungen indes nicht aus. Auch der Energiehunger angeschlossener Komponenten, die Umgebungstemperatur, und die Taktfrequenz spielen eine entscheidende Rolle. Wer das berücksichtigt, kann die Zeit bis zum erforderlichen Neuladen der Batterie auf erträgliche Werte verlängern.
Auf Basis des Beispiels einer Wetterstation lassen sich natürlich viele Erweiterungenhinzufügen, angefangen von einem e-Ink-Display zur Anzeige der Messergebnisse bis hin zu einer LiPo-Batterie oder Solarzelle für die Energieversorgung.Hauptsache, die Energiebilanz stimmt.
Viel Spaß mit Ihren eigenen Experimenten im Schlaflabor.
URL dieses Artikels: https://www.heise.de/-6046517
Internationalisierung ist in der Web-Entwicklung ein Thema, das häufig leider immer noch viel zu kurz kommt. Für die meisten endet der Begriff Internationalisierung auch schon bei der Übersetzung von Texten. Das ist jedoch eine Problemstellung, die der Browser nach wie vor den etablierten Bibliotheken überlässt. Wo alle modernen Browser jedoch mittlerweile dank der Intl API durchgängig punkten können, sind Themen wie die lokalisierte Formatierung von Zahlen, Datums- und Zeitwerten. Neben diesen Angaben bringt die Intl API noch Features zum lokalisierten String-Vergleich sowie Regeln für die Behandlung von Ein- und Mehrzahl.
Alle JavaScript-Umgebungen, also die bekannten Browser, Node.js und sogar der Internet Explorer, unterstützen die Intl API in Form des globalen Intl-Objekts. Es enthält neben der getCanonicalLocales-Methode die folgenden Konstruktoren:
Collator: Klasse für sprachabhängigen String-Vergleich
DateTimeFormat: Formatierung von Datums- und Zeitwerten
NumberFormat: Formatierung von Zahlen wie Währungen oder Prozentwerten
PluralRules: Unterstützung bei der Behandlung von Ein- und Mehrzahl
Die Intl API setzt durchgängig auf Gebietsschema-Informationen zur Steuerung der einzelnen Features. Zu diesem Zweck akzeptieren die Konstruktoren der Schnittstelle Locale-Strings, die den BCP-47-Vorgaben [1] folgen, also beispielsweise “de” oder “de-DE”. Erzeugt ein Script eine neue Instanz einer der Intl-Klassen, akzeptiert diese entweder ein Array von Locales, eine einzelne Locale oder keinen Wert. Ein ungültiger Wert führt dazu, dass der Browser einen RangeError auswirft.
Die getCanonicalLocales-Methode liefert für eine Eingabe einen gültigen Locale-Wert zurück und verhält sich dabei wie die Konstruktoren der Intl-Unterklassen. Den Wert “DE” wandelt die Methode in “de” um, ein Array mit den Werten “de”, “de-de” und “DE-DE” wird zu “de” und “de-DE” und die Eingabe “de-DEU” führt zu einem RangeError. Bei einem Array entfernt die getCanonicalLocales-Methode alle Duplikate.
Alle Intl-Klassen verfügen über eine statische Methode mit dem Namen supportedLocalesOf. Diese Methode akzeptiert einen Locale-String oder ein Array von Locales und liefert ein Array von Locales zurück, das die jeweilige Klasse direkt unterstützt, ohne auf Standard-Locale zurückzugreifen.
Collator: String-Vergleiche
JavaScript verfügt über die Array.prototype.sort-Methode zur Sortierung von Arrays. Diese Methode sortiert die einzelnen Elemente anhand ihrer UTF-16-Codewerte. Alternativ akzeptiert die Sort-Methode eine Vergleichsfunktion. Diese Vergleichsfunktion erhält bei jedem Aufruf zwei Werte, die miteinander verglichen werden. Ist der erste Wert kleiner als der zweite, gibt die Vergleichsfunktion eine Zahl kleiner als Null zurück, ist der erste Wert größer, wird eine Zahl größer Null zurückgegeben. Sind beide Werte gleich, ist der Rückgabewert der Vergleichsfunktion Null. Je nach Region, in der die Applikation ausgeführt wird, kann das Verhalten dieser Sortierung unterschiedlich sein. Die Collator-Klasse der Intl API nimmt Entwicklern diese Aufgabe ab und sorgt dafür, dass die Sortierung für die gewählte Region passend ist.
Die compare-Methode einer Collator-Instanz hat eine zur sort-Methode der JavaScript Arrays passende Signatur, akzeptiert also zwei Werte und gibt entweder 1, 0 oder –1 zurück. Das folgende Beispiel sortiert das Array mit den Werten “Birnen”, “Äpfel” und “Zitronen” für die Locale “de-DE”.
const col = new Intl.Collator('de'); const arr = [ 'Birnen', 'Äpfel', 'Zitronen' ]; console.log(arr.sort(col.compare)); // ["Äpfel", "Birnen", "Zitronen"]
Wie zu erwarten, ist das Ergebnis “Äpfel, Birnen, Zitronen”. Für die Locale “sv-SE”, also Schwedisch in Schweden, sieht das Ergebnis ganz anders aus, da hier das “Ä” nach dem “Z” einsortiert wird. Und das ist nur ein Beispiel, bei dem die Collator-Klasse hilfreich ist. Ein weiterer typischer Anwendungsfall ist das Sortieren von Zahlenwerten. Standardmäßig sortiert JavaScript folgendermaßen: 1, 132, 22. Die erste Ziffer ist hier also jeweils ausschlaggebend und nicht der Zahlenwert. Die Collator-Klasse sieht eine Lösung vor, nach der numerische Werte korrekt interpretiert werden können. Dieses Verhalten ist jedoch deaktiviert und muss bei der Erzeugung der Collator-Instanz zunächst aktiviert werden. Das erfolgt entweder über die Unicode-Erweiterung “kn” der Locale-Zeichenkette, also in diesem Fall beispielsweise “de-u-kn", oder über die numeric-Option, deren Wert auf true gesetzt wird. Solche Optionen akzeptieren alle Intl-Konstruktoren in Form eines Objekts als zweites Argument bei der Instanziierung.
const col = new Intl.Collator('de', {numeric: true}); const arr = [132, 1, 22 ]; console.log(arr.sort(col.compare)); // [1, 22, 132]
Zusätzlich zu diesen Optionen unterstützt der Collator noch weitere, beispielsweise wie Groß- und Kleinschreibung unterschieden werden sollen. Diese insgesamt flexibele Klasse sorgt dafür, dass für einen Stringvergleich kaum noch benutzerdefinierte Funktionen geschrieben werden müssen.
DateTimeFormat: Formatierung von Datum und Zeit
Eine der großen Schwächen der JavaScript Date-Klasse ist, dass sich die mit ihr erzeugten Objekte kaum formatiert ausgeben lassen. Dafür benötigt eine Applikation immer eine zusätzliche Bibliothek. Die Intl API löst zumindest einen Teil dieser Probleme. Die toString-Methode des Date-Objekts liefert den folgenden Wert: “Fri Jun 05 2020 10:15:00 GMT+0200 (Central European Summer Time)”. In einer Web-Applikation ist eine solche Zeichenkette jedoch wenig sinnvoll. Normalerweise sollen nur Datum oder Zeit in der korrekten Formatierung angezeigt werden – also beim Datum etwa 05.06.2020, 05/06/2020 oder 06/05/2020. Die Date-Klasse unterstützt eine solche Formatierung nicht direkt, sondern nur über einzelne Methoden wie getDay oder getMonth, die allerdings nur einstellige Ausgaben für den 5. beziehungsweise Juni liefern. Entwickler müssen hier also wieder selbst tätig werden. Die DateTimeFormat-Klasse der Intl API liefert mit ihrer format-Methode eine elegantere Lösung:
Eine Änderung der Locale auf “en-US” führt zur Ausgabe von “06/05/2020” und “en-GB” sorgt für “05/06/2020”. Das Options-Objekt der DateTimeFormat-Klasse entscheidet über das Aussehen und auch den Inhalt der einzelnen Elemente des Date-Objekts. Wird die day-Eigenschaft beispielsweise weggelassen, fällt auch die Tagesangabe bei der Ausgabe weg. Die meisten Eigenschaften des Options-Objekts unterstützen die Werte “2-digit”, also auf zwei Stellen aufgefüllt, und “numeric”, was je nach Wert eine einstellige, zweistellige oder bei der Jahreszahl eine vierstellige Ausgabe produziert. Bei der Formatierung von Zeitwerten verhält sich die DateTimeFormat-Klasse wie das Datum:
Beim Formatieren von Datum und Uhrzeit hilft die DateTimeFormat-Klasse, allerdings sind die Möglichkeiten eingeschränkt. Eine komplett freie Formatierung ist nicht vorgesehen. Es gibt aber die formatToParts-Methode, die jeden einzelnen Teil des Ergebnisses als ein separates Array-Element enthält:
Mit den einzelnen Teilen des resultierenden Objekts lassen sich beliebige Formate realisieren. Hier ist jedoch umfangreiche Handarbeit erforderlich – es wird jedoch deutlich einfacher als mit dem nativen Date-Objekt von JavaScript.
NumberFormat: Zahlen formatieren
Die NumberFormat-Klasse kümmert sich, wie der Name andeutet, um das Formatieren von Zahlenwerten und zwar in drei verschiedenen Arten. Die style-Eigenschaft bestimmt, ob es sich um eine gewöhnliche Zahl (decimal), einen Währungswert (currency) oder einen Prozentwert (percent) handelt. Der Standardwert für die Option style ist “decimal” und useGrouping weist “true” auf, sodass immer ein Tausendertrennzeichen verwendet wird und die im Beispiel verwendete Option auch weggelassen werden könnte. Der nachfolgende Code gibt die Zahl 3141,59 mit Tausendertrenner und zwei Nachkommastellen aus:
const number = Math.PI * 1000; const numberFormatter = new Intl.NumberFormat('de-DE', { useGrouping: true, maximumFractionDigits: 2, });
Mit der Option useGrouping kann gewählt werden, ob der Tausendertrenner angezeigt werden soll. Die Änderung der Locale im Konstruktor auf den Wert “en-US” führt zur Ausgabe von 3,141.59.
Ein weiteres wichtiges Feature der NumberFormat-Klasse ist die Formatierung von Währungswerten. Dieses Feature wird durch die style-Eigenschaft mit dem Wert “currency” aktiviert. Zusätzlich dazu muss die Währung über die currency-Eigenschaft übergeben werden. Erfolgt dies nicht, wirft der Browser einen TypeError aus. Zur Auswahl der Werte stehen die ISO-4217-Währungscodes wie “EUR” oder “USD” bereit. Der nachstehende Code gibt den Wert €3,141.59 aus:
const number = Math.PI * 1000; const numberFormatter = new Intl.NumberFormat('en-GB', { style: "currency", currency: "EUR", maximumFractionDigits: 2, });
Die currencyDisplay-Eigenschaft steuert die Anzeige des Währungssymbols. Der Standardwert “symbol” zeigt in diesem Beispiel das Euro-Symbol an. Weitere mögliche Werte sind “code” für den ISO-Code und “name” für den ausführlichen Namen der Währung.
PluralRules: Einzahl oder Mehrzahl, das ist hier die Frage
Eine Instanz der PluralRules-Klasse gibt mit der select-Methode für eine Zahl eine Zeichenkette zurück, die angibt, ob es sich um Ein- oder Mehrzahl handelt. Zugegebenermaßen ist diese Klasse für die deutsche Locale eher unspektakulär. Bei der type-Option mit dem Standardwert “cardinal” gibt die Methode für die Zahl 1 den Wert “one” und für alle übrigen den Wert “other” zurück. Dieser Typ steht für Mengen. Mit dem “ordinal”-Typ kann gezählt werden, was für die deutsche Locale durchgängig die Werte “other” zurückgibt. Anders sieht die Situation für die Locale “en-US” aus, wie folgendes Codebeispiel zeigt:
const arr = new Array(24).fill('').map((v, i) => i); const pr = new Intl.PluralRules('en-US', {type: 'ordinal'});
arr.forEach(v => console.log(v, pr.select(v)));
Für alle Werte, die auf 1 enden, gibt die select-Methode “one”, für 2 den Wert “two”, für 3 den Wert “few” aus, und für alle weiteren Eingaben liefert select die Ausgabe “other” zurück. Eine Umstellung auf den “cardinal”-Typ liefert wieder “one” für 1 und “other” für die übrigen Werte zurück.
Fazit: hilft uns die Intl API wirklich?
Die Intl API bietet einige sinnvolle Erweiterungen für den JavaScript-Sprachstandard, um internationale Applikationen zu ermöglichen. Das Thema Übersetzungen spart die Schnittstelle aber komplett aus und überlässt es zusätzlichen Bibliotheken. Aber gerade die Formatierung von Datums-, Zeit- und Zahlenwerten löst eine Reihe von Standardproblemen auf elegante und solide Art.
URL dieses Artikels: https://www.heise.de/-6040598
Links in diesem Artikel: [1] https://tools.ietf.org/html/bcp47