FreshRSS

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

Maple Mini - ein weiteres STM32F103-Board

Von heise online

zurück zum Artikel

Nachdem im letzten Teil die Blue Pill im Fokus stand, konzentriert sich der vorliegende Kurzbeitrag auf das Maple Mini Board. Auch dieses enthält einen ARM Cortex M3 mit 72 MHz Taktfrequenz. Im Gegensatz zur Blue Pill lässt das Maple Mini einen Anschluss über Micro-USB zu.

Das Maple Mini Board

Hersteller des Maple Mini war ursprünglich die Firma LeafLabs, die das Board im Jahr 2011 auf den Markt brachte. LeafLabs liefert das Board zwar nicht mehr, hat aber dessen Design als Open Source zur Verfügung gestellt.

Das Maple Mini von LeafLabs gibt es bereits seit 2011
Das Maple Mini von LeafLabs gibt es bereits seit 2011

Das ist der Grund, warum sich heute zahlreiche Klone im Angebot der Online-Händler befinden. Bei ebay ist ein Board für rund 1,87€ aus chinesischer Produktion zu haben. Speziell die Nachbauten von Baite zeichnen sich durch eine sehr gute Qualität aus.

Ein Maple Mini Klon mit guter Qualität
Ein Maple Mini Klon mit guter Qualität

Bezüglich seiner Leistungsdaten entspricht ein Maple Mini der im letzten Beitrag [1] vorgestellten Blue Pill, weshalb sich dieser Artikel die erneute Beschreibung spart. Jedenfalls ist auch das Maple Mini in Sachen Performanz schon rein rechnerisch einem Arduino Uno Board um eine Größenordnung voraus.

Um ein Maple Mini wie ein Arduino Board in der Arduino IDE zu programmieren, gibt es den STM32duino Core, den wir ebenfalls in der letzten Blog-Folge kennengelernt haben. Auch seine Installation war dort schon sehr ausführlich beschrieben.

Aus Programmierersicht liegt im STM32duino Core folgende Pin-Belegung beim Maple Mini vor. Wie bereits bei der Blue Pill erläutert, müssen Cores für Arduino die nativen Pins auf ein neues Mapping abbilden.

Nur die Pins mit grün-weisser oder blau-weisser Beschreibung stellt der STM32Duino Core dem Entwickler zur Verfügung
Nur die Pins mit grün-weisser oder blau-weisser Beschreibung stellt der STM32Duino Core dem Entwickler zur Verfügung

Etwas gewöhnungsbedürftig beim Maple Mini ist das Fehlen eine Power-LED. Es ist also nicht immer ersichtlich, ob das Board läuft. Auf der anderen Seite hat dies den Vorteil, dass eine Schaltung dadurch im laufenden Betrieb ein paar Milliampere spart.

Auf dem Board sind rechts zwei Knöpfe zu sehen, die reset und but=32 heißen. Die Funktion des RESET-Knopfs dürfe eindeutig sein. Mit ihm versetzen Entwickler das Board in den Flashmodus. Nach dem Aufspielen der neuen Firmware beziehungsweise des neuen Sketches führt ein Betätigen des Knopfes das Board in den Ausführungsmodus. Der zweite Knopf lässt sich auch für eigene Anwendungen benutzen.

Im Gegensatz zur Blue Pill entfällt beim Maple Mini das lästige indirekte Verbinden mit einem UART-USB-to-TTL-Adapter. Stattdessen genügt es, das Board über Micro-USB direkt am Entwicklungsrechner anzuschließen.

Programmierung des Maple Mini

Nach Installation des STM32duino Cores (siehe Erläuterungen im letzten Beitrag [2]) steht in der Arduino IDE auch das Maple Mini Board zur Auswahl:

In der Arduino IDE steht das Maple Mini Board nach Installation des STM32duino Core zur Verfügung
In der Arduino IDE steht das Maple Mini Board nach Installation des STM32duino Core zur Verfügung

Bei Linux (siehe hier [3]) und Windows (siehe hier [4]) sind im Gegensatz zu macOS zuvor noch ein paar kleine Schritte notwendig, um mit dem Maple Mini und der Arduino IDE (STM32duino) loslegen zu können. Bei Windows betrifft das zum Beispiel die notwendigen Treiber für USB.

Beispielsanwendung Thermometer

In der Beispielsanwendung ist ein OLED-Display des Typs SSD1306 mit 124 x 64 Auflösung über I2C am Maple Mini angeschlossen. Zudem befindet sich ein DS18B20-Temperatursensor in der Schaltung, den wir mit Pin 2 des Maple Mini verbinden. Zusätzlich hängt ein 4.7KΩ-Widerstand zwischen Signalausgang des Temperatursensors und dem Pluspol der Stromversorgung.

Hier eine Impression vom laufenden System:

Das laufende System auf Basis des Maple Mini von Baite mit Temperatursensor und OLED-Display
Das laufende System auf Basis des Maple Mini von Baite mit Temperatursensor und OLED-Display. Links im Bild ist übrigens eine Blue Pill

Jede Sekunde erfolgt eine Messung der Temperatur und deren Ausgabe am OLED-Display.

Um die Schaltung nachbauen zu können, habe ich wie immer die Schaltung mittels Fritzing auf "Papier" gebannt.. Es ergibt sich folgendes Schaltungsdiagramm:

Fritzing Schaltungsdiagramm für SSD1306 OLED und DS18B20 Temperatursensor an Maple Mini
Fritzing Schaltungsdiagramm für SSD1306 OLED und DS18B20 Temperatursensor an Maple Mini

Zum Glück belohnt das Schicksal die Tüchtigen. Für die Hardwarezugriffe auf die Komponenten der Schaltung haben andere Maker bereits existierende Bibliotheken angepasst. Für den Sketch sind folgende Bibliotheken notwendig:

  • OneWire.h für den Zugriff auf das OneWire-Protokoll
  • DallasTemperature.h für das Auslesen des Temperatursensors
  • Adafruit_GFX.h enthält Grafikroutinen für die Displayausgabe
  • Adafruit_SSD1306_STM32.h ist die Implementierung für STM32-Boards auf SSD1306-OLED-Displays mit Auflösung 128 x 64.

Als Basis für die Implementierung verwenden Sie das über File > Examples > Examples for Maple Mini > Adafruit_SSD1306 > ssd1306_128x64_i2c_STM32 verfügbare Projekt.

Achtung: Meldet der Compiler beim Übersetzen des unten abgebildeten Sketches den Fehler, dass er die Methode swap(x, y) nicht kennt, fügen Sie in die Headerdatei Adafruit_SSD1306_STM32.h vor der Klassendefinition class Adafruit_SSD1306 folgende Definition ein:

#define swap(a, b) { int16_t t = a; a = b; b = t; }

Dann sollte es problemlos funktionieren.

Der Sketch selbst ist nicht weiter aufregend. Im Setup initialisiert das Programm den Dallas 18B20 Sensor und das OLED-Display.

In der Ereignisschleife fragt der Code zunächst jede Sekunde den Sensor ab, und gibt den gemessenen Wert an der Anzeige aus.

//************************************************
// Maple Mini plus OLED SSD 1306 mit 128 x 64
// und DS18B20 Dallas Temperatursensor
// Demonstration zur Verwendung der Bibliotheken
// für Maple Mini in der Arduino IDE
//************************************************

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306_STM32.h>

// Zutaten: 1-Wire Protokoll und Sensor-Bibliothek
#include <OneWire.h>
#include <DallasTemperature.h>

// Der Bus hängt an Port 2 des Maple Mini Boards

#define ONE_WIRE_BUS 2

// 1-Wire-Protokoll initialisieren
OneWire oneWire(ONE_WIRE_BUS);

// ... und Referenz übernehmen
DallasTemperature sensors(&oneWire);

// OLED Display Typ 1306 mit 128 x 64 Pixel
// an I2C-Bus

// Adresse müssen Sie ggf. an Ihr Board
// anpassen !!!

const byte i2cAddress = 0x3C;

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

// Setup von Sensor und Display an I2C
void setup() {
// Bibliothek initialisieren

sensors.begin();

// Display vorbereiten
display.begin(SSD1306_SWITCHCAPVCC, i2cAddress);
display.display();
}

// Unsere Eventloop:
void loop() {
// Alle anwesenden Sensoren um Temperatur bitten
sensors.requestTemperatures();
// Wir nehmen den erstbesten
double temp = sensors.getTempCByIndex(0);
// Temperatur ausgeben
displayTemperature(temp);
// und eine Sekunde warten
delay(1000);
}

// Routine zur Temperaturausgabe:
void displayTemperature(double temperature) {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Temperatur");
display.println();
display.setTextSize(3);
display.println(temperature);
display.display();
}

Sobald die IDE das Programm erfolgreich kompiliert hat, fordert die Ausgabe dazu auf, das Maple Mini Board durch Druck des RESET-Knopfs in den Ausführungsmodus zu setzen. Erst danach beginnt die eigentliche Programmausführung.

Übersetzung in der Arduino IDE. Zum Flash-Upload verwendet die STM32-Werkzeugkette dfu-util
Übersetzung in der Arduino IDE. Zum Flash-Upload verwendet die STM32-Werkzeugkette dfu-util

Programmieralternativen

Im vorangegangenen Teil über die Blue Pill haben wir bereits einige Alternativen zur Arduino IDE kennengelernt, etwa STM32CubeMX oder die OpenSTM32 System Workbench. Daher kann dieser Abschnitt kurz bleiben.

Weitgehend unerwähnt sollen an dieser Stelle kommerzielle IDEs wie Keil bleiben.

Auch die interaktive und Web-basierte mbed-Plattform von ARM lässt sich für den Maple Mini nutzen. Ursprünglich gab es auch noch eine eigene Maple IDE, die aber inzwischen kaum noch jemand verwendet. Heute macht es ohnehin mehr Sinn, die Arduino IDE in Kombination mit dem STM32duino Core einzusetzen.

Fazit

Im letzten und in diesem Artikel lag der Fokus auf zwei Boards aus der STM32F103-Familie, die Blue Pill und das Maple Mini Board. Beide bieten exzellente Leistung zu einem guten Preis. Gerade für rechenintensivere Anwendungen macht der Einsatz dieser Controller Sinn. Dank STM32duino-Unterstützung erscheinen die Boards in der Arduino IDE wie Arduino-Boards, was den Umstieg oder besser Aufstieg spürbar leichter macht.

Auch wenn nicht immer alle (Arduino-)Bibliotheken zur Verfügung stehen, arbeitet die Community kontinuierlich daran, den Leistungsumfang zu erweitern. Für eigene Problemstellungen findet sich daher auch fast immer eine helfende und kompetente Hand. Daher brauchen sich selbst Anfänger nie verloren fühlen. Allerdings sind Blue Pill und Maple Mini nicht mehr ganz so pflegeleicht wie ihre reinen Arduino-Cousins, und erfordern wesentlich mehr Handarbeit und technisches Geschick.

Aus meiner Sicht überwiegen aber die Vorteile den Nachteilen deutlich. Bei einem Preis von wenigen Euros gibt es nicht wirklich etwas zu verlieren. Grund genug, auch in Zukunft immer wieder einen Blick auf die Welt der STM32-Embedded Controller zu werfen.


URL dieses Artikels:
http://www.heise.de/-4010625

Links in diesem Artikel:
[1] https://www.heise.de/developer/artikel/Keine-bittere-Pille-Die-Blue-Pill-mit-ARM-Cortex-M3-4009580.html
[2] https://www.heise.de/developer/artikel/Keine-bittere-Pille-Die-Blue-Pill-mit-ARM-Cortex-M3-4009580.html
[3] https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki/Linux
[4] https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki/Maple-drivers

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 05. April 2018 um 07:00

Keine bittere Pille - Die Blue Pill mit ARM Cortex M3

Von heise online

zurück zum Artikel

Im Arduino-Universum existieren von einigen Herstellern Arduino-kompatible Boards, die mit anderen Prozessoren als denen aus der ATMEL-Microprozessorfamilie aufwarten. Teensy, ESP8266 und ESP32 haben wir bereits kennengelernt. Von STMicroelectronics gibt es das Board STM32F103C8T6, das seine Anhänger Blue Pill nennen - ein Board mit ausgezeichnetem Preis-/Leistungsverhältnis.

Welcome, on Board

Warum die Blue Pill so heißt wie sie heißt, lässt sich dem folgenden Profilbild entnehmen:

Der Microcontroller STM32F103C8T6, oft nur unter seinem Kosenamen Blue Pill bekannt, liefert hohe Leistung für wenig Geld
Der Microcontroller STM32F103C8T6, oft nur unter seinem Kosenamen Blue Pill bekannt, liefert hohe Leistung für wenig Geld (Bild: http://wiki.stm32duino.com)

Mit einer 32Bit ARM-Cortex-M3-Architektur und einer Taktfrequenz von 72 MHz steckt die Blue Pill einen Arduino auf Basis des 8-Bit Prozessors ATMega328P mit 16 MHz Taktfrequenz performanzmäßig locker in die Tasche. 64 KB (manchmal auch 128 KB) Flashspeicher und dazu 20 KB RAM bieten genügend Reserven für viele Aufgabenstellungen. Zudem beinhaltet das Board eine mit einem separaten Quarz auf 32 MHz getaktete Echtzeituhr (RTC). Im Normalbetrieb unterstützt der Mikrocontroller ein Logiklevel von 3.3V. Es sind zwar auch 5V möglich, wobei einige, aber nicht alle Pins 5V vertragen.

Für eine Blue Pill ist beim Dealer ein Obolus zwischen 2 und 5 Euro zu entrichten. Beschaffungskriminalität lohnt sich also nicht. Wie immer gilt: Je kleiner der Preis, desto näher liegt der Händler bei China.

Das Board verfügt über mehrere serielle Ports, und über mehrere SPI- und I2C-Busanschlüsse (siehe nachfolgende Abbildung des Pin-Layouts). Ein ADC mit 12-Bit-Auflösung lässt die genauere Messwerterfassung von Sensoren zu.

Und natürlich darf eine essenzielle Information nicht fehlen: die eingebaute LED der Blue Pill liegt am Pin PC13.

Die Pinbelegung zeigt, dass die Blue Pill einige nützliche Features besitzt, unter anderem mehrere serielle Ports, CAN- SPI- und I2C-Anschlüsse
Die Pinbelegung zeigt, dass die Blue Pill einige nützliche Features besitzt, unter anderem mehrere serielle Ports, CAN- SPI- und I2C-Anschlüsse

Mehr Details erfährt der Entwickler in einem von STMicroelectronics bereitgestellten Dokument[1].

Hinweis

Beim Performanzvergleich zwischen Cortex-M3 und ATMega328P lauern Fallstricke. Ein Beispiel gefällig: In der Arduino IDE gibt es zwar double und float als Datentypen. Beide sind auf Arduino-Boards aber identisch und umfassen jeweils 32 Bit. Auf einem Cortex-M3-Board wie der Blue Pill sind Werte des Typs double aber 64-Bit breit, haben also doppelte Größe. Beim Benchmarking ist daher wichtig, nicht Äpfel mit Birnen zu vergleichen.

Entwicklungshilfen

In dieser Folge konzentriere ich mich darauf, wie sich das Board mit Hilfe der Arduino IDE programmieren lässt. Allerdings ist das nur eine der Möglichkeiten. Die meisten anderen Möglichkeiten für den Entwickler sind teilweise besser geeignet - zumindest für Pros. Leider habe ich an dieser Stelle nicht die Möglichkeit, diese anzusprechen. Wenigstens sollen einige dieser Optionen zur Sprache kommen:

  • Mittels des STM32 Flash Tools[2] können Entwickler ihren Code beispielsweise mit Microsoft Visual Studio erstellen und das Ergebnis über den UART auf das Board laden.
  • Das umfangreiche Werkzeug STM32CubeMX[3] erlaubt die Codegenerierung für Projekte und entsprechende Werkzeugketten, ebenso die Erzeugung von Code für komplexere Embedded-Aufgaben mittels grafischer Wizards. Dabei lassen sich alle möglichen Bibliotheken aus dem STM32Cube importieren.
  • Über ST-Link V2, einen In-Circuit Debugger and Programmer, schließen Entwickler die Blue Pill an ihren Rechner an und nutzen zur Programmierung z.B. die kostenlose OpenSTM32[4] System Workbench auf Basis von Eclipse. Wer ein Nucleo-64-Board von STM besitzt, kann dessen ST-Link-Schnittstelle zum Programmieren benutzen.
  • Natürlich bevorzugen einige Entwickler Bare Metal Programming. Wie das geht, zeigt trebisky auf seiner Github-Seite[5].

Generell zu empfehlen ist auch die Blog-Seite[6], die über mehrere dieser Programmieroptionen schreibt.

Integration in die Arduino IDE

Zum Glück gibt es eine große Community namens STM32duino, die sich um das Integrieren von STM32-Boards in das Arduino-Ökosystem kümmert. Viele Informationen, Tipps und Tricks sind auf deren Website[7] zu finden. Ein Besuch dieser Webseiten ist daher sehr zu empfehlen.

Doch nun in medias res. Um Unterstützung für die Blue Pill in die Arduino IDE zu integrieren, bedarf es mehrere Schritte. Dazu nötig ist mangels ST-Link-Programmer eine serielle Verbindung zu einem FTDI-Board oder einem anderen UART-USB-to-TTL-Adapter.

Schritt 1: Blue Pill mit UART-USB-to-TTL-Adapter verbinden

Zunächst sind die notwendigen Verbindungen zwischen Blue Pill und dem verwendeten UART-USB-to-TTL-Adapter zu etablieren (siehe Abbildung). Nach dem Anschluss des Ganzen per USB an den Computer blinkt normalerweise die LED an PC13, weil der Blink-Sketch bei der Produktion zu Testzwecken aufgespielt wurde.

Was genau zu tun ist:

  • Die Stromversorgung des FTDI-Adapter (Vcc, GND) verbinden wir mit 3.3V und GND an der Blue Pill.
  • An Pin A9 liegt der TX-Ausgang der Blue Pill und ist mit dem RX-Eingang des Adapters zu verdrahten.
  • Pin A10 der Blue Pill entspricht dem RX-Eingang und ist entsprechend mit dem TX-Ausgang des Adapters zu verbinden.
Verbindung von Blue Pill und UART-USB-to-TTL-Adapter
Verbindung von Blue Pill und UART-USB-to-TTL-Adapter

Schritt 2: Board-Manager für Arduino SAM Boards laden

Im nächsten Schritt gehen Sie über Tools > Boards > Boards Manager, suchen nach Arduino SAM Boards (ARM Cortex-M3) und installieren den entsprechenden Board-Manager.

Im zweiten Schritt ist die Installation des Boardmanagers für ARM Cortex M3 Boards notwendig
Im zweiten Schritt ist die Installation des Boardmanagers für ARM Cortex M3 Boards notwendig

Schritt 3: STM32duino Coreinstallieren

Roger Clark ist Master des Githubs für STM32-basierte Arduino Cores. Laden Sie sich über dessen Github-Seite[8] das gesamte Paket als ZIP-Archiv herunter. Damit lassen sich Blue Pills in der Arduino IDE wie native Arduino Boards programmieren.

Auf der Github-Seite von STM32DUINO ist das Zip-Archiv verfügbar
Auf der Github-Seite von STM32DUINO ist das Zip-Archiv verfügbar

Das Archiv gilt es zu entpacken und das daraus resultierende Verzeichnis Arduino_STM32 in das Sketchbook-Verzeichnis der Arduino IDE zu kopieren, zum Beispiel

  • unter Windows als Unterverzeichnis von My Documents\Arduino\Hardware
  • unter macOS als Unterverzeichnis von ~/Documents/Arduino/hardware

Sollte das Hardware-Verzeichnis noch nicht existieren, muss es angelegt werden. Danach verlassen Sie die Arduino IDE und starten die IDE erneut. Jetzt können Sie nicht nur Blue Pill, sondern auch andere Boards von STM unter der Arduino IDE nutzen.

Schritt 4: Blue Pill Einstellungen setzen

Gehen Sie in der Arduino IDE unter Tools und konfigurieren Sie das entsprechende Board (siehe links oben in der Abbildung)..

Für die Blue Pill ist das die Generic STM32F103C8 series die richtige Wahl als Board
Für die Blue Pill ist das die Generic STM32F103C8 series die richtige Wahl als Board

Unter Menüpunkt Variant sollten Sie einstellen: STM32F103C8 (20k RAM. 64k Flash).

Danach als Upload method: "Serial" (es sei denn, Sie verwenden eine andere Variante des Programmers wie etwa ST-LINK).

Unter Port spezifizieren Sie den von dem UART-USB-to-TTL Adapter verwendeten seriellen Port. Nutzen Sie etwas anderes als einen FTDI-basierten Adapter, ist zuvor eventuell das zusätzliche Installieren eines für Ihren Adapter bestimmten USB-Treibers notwendig.

Schritt 5: Testsketch programmieren

Im Menüpfad File > Examples > A_STM32-Examples > Digital können Sie als Testprogramm beispielsweise Blink wählen. Port PB1 ändern Sie dabei in PC13. Oder Sie schreiben einfach einen eigenen Testsketch. Mein simpler Sketch für das LED-Blinken sieht wie folgt aus:

void setup() {
pinMode(PC13, OUTPUT); // OnBoard-LED liegt an PC13
Serial.begin(9600); // Ausgabe am seriellen Monitor
}

void loop() {
digitalWrite(PC13, !digitalRead(PC13)); // LED invertieren
Serial.println(digitalRead(PC13) ? "low" : "high"); // -> ser. Monitor
delay(1000); // Pause einlegen
}

Bevor sich der Sketch auf die Blue Pill laden lässt, ist das Setzen des Blue Pill in den Programmiermodus wichtig. Zu diesem Zweck bewegen Sie den oberen gelben Jumper (BOOT0) von Position 0 auf 1 (im nachfolgenden Bild von links nach rechts), und drücken anschließend die RESET-Taste. Der untere Jumper BOOT1 bleibt dabei stets unverändert.

Den BOOT1-Jumper können Sie übrigens für eigene Anwendungen nutzen. Er hat sonst keine andere Funktion.

Um einen Sketch hochlasden zu können, muss der BOOT0-Jumper (oben) auf 1 gestellt, und anschließend ein Reset durchgeführt werden.
Um einen Sketch hochladen zu können, muss der BOOT0-Jumper (oben) auf 1 gestellt, und anschließend ein Reset durchgeführt werden.

Nun kann die Arduino IDE den kompilierten Sketch auf die Blue Pill laden. Hat das geklappt, passiert folgendes: Die Onboard-LED blinkt. Im seriellen Monitor sehen Sie zeilenweise eine Folge von "low" und "high"-Nachrichten.

Soll der Sketch nach einer Änderung neu auf das Board geladen werden und ist der BOOT0-Jumper immer noch auf Stellung 1 positioniert, genügt ein Reset vor dem Sketch-Upload. Wollen Sie hingegen ein Überschreiben des Sketches verhindern, setzen Sie diesen Jumper auf Position 0 zurück.

Port Mapping

Um die in der Arduino IDE verwendbaren Port-Namen zu kennen, genügt ein Blick auf die Implementierung des STM32duino Core, genauer gesagt auf die Headerdatei board.h:

...Header board.h ....

#define BOARD_NR_USARTS 3
#define BOARD_USART1_TX_PIN PA9
#define BOARD_USART1_RX_PIN PA10
#define BOARD_USART2_TX_PIN PA2
#define BOARD_USART2_RX_PIN PA3
#define BOARD_USART3_TX_PIN PB10
#define BOARD_USART3_RX_PIN PB11

#define BOARD_NR_SPI 2
#define BOARD_SPI1_NSS_PIN PA4
#define BOARD_SPI1_MOSI_PIN PA7
#define BOARD_SPI1_MISO_PIN PA6
#define BOARD_SPI1_SCK_PIN PA5

#define BOARD_SPI2_NSS_PIN PB12
#define BOARD_SPI2_MOSI_PIN PB15
#define BOARD_SPI2_MISO_PIN PB14
#define BOARD_SPI2_SCK_PIN PB13

#define BOARD_NR_GPIO_PINS 35
#define BOARD_NR_PWM_PINS 12
#define BOARD_NR_ADC_PINS 9
#define BOARD_NR_USED_PINS 4

#define BOARD_JTMS_SWDIO_PIN 22
#define BOARD_JTCK_SWCLK_PIN 21
#define BOARD_JTDI_PIN 20
#define BOARD_JTDO_PIN 19
#define BOARD_NJTRST_PIN 18

#define BOARD_USB_DISC_DEV GPIOB
#define BOARD_USB_DISC_BIT 10

// Note this needs to match with the PIN_MAP array in board.cpp
enum {
PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, PA11, PA12, PA13,PA14,PA15,
PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11, PB12, PB13,PB14,PB15,
PC13, PC14,PC15
};

...

Beim Entwickeln in der Arduino IDE können Programmierer die obigen Bezeichner nutzen.

Demobeispiel

Jetzt soll ein etwas komplexerer Sketch demonstrieren, dass sich durchaus für die Blue Pill Bibliotheken in der Arduino IDE so nutzen lassen als hätten wir ein natives Arduino-Board vor uns. Im Beispiel ist ein Temperatursensor des Typs Dallas DS18B20 angeschlossen. Zu dessen Nutzung hat Maxim (der heutige Name des Herstellers) den OneWire-Bus eingeführt. Den OneWire-Bus und den Sensor hatte ich bereits in einem früheren Beitrag[9] illustriert. Zwischen Dateneingang und Versorgungseingang des Sensors ist ein 4.7 KΩ notwendig.

Das Schaltbild erweitert sich wie folgt:

Blue Pill und DS18B20 gehen gemeinsame Wege
Blue Pill und DS18B20 gehen gemeinsame Wege

Der Sensor (links oben in der Schaltung) ist über Pin PA2 angeschlossen.

Der Sketch ist eher einfach gestrickt. Er soll einfach in jedem Zyklus den Sensorwert des DS18B20 erfassen und am seriellen Monitor ausgeben:

//************************************************
// Blue Pill plus DS18B20 Dallas Temperatursensor
// Demonstration zur Verwendung der Bibliotheken
// fuer Blue Pill in der Arduino IDE
//************************************************

// Zutaten: 1-Wire Protokoll und Sensor-Bibliothek
#include
#include

// Der Bus haengt an Port PA2 des STM32F103CT6 Boards
#define ONE_WIRE_BUS PA2

// 1-Wire-Protokoll initialisieren
OneWire oneWire(ONE_WIRE_BUS);

// ... und Referenz übergeben
DallasTemperature sensors(&oneWire);

// Generelles Setup von seriellem Monitor und der
// Sensor-Bibliothek

void setup(void)
{
Serial.begin(9600); // seriellen Monitor starten
Serial.println("Demo des DS18B20 Sensors an der Blue Pill");

// Bibliothek initialisieren
sensors.begin();
}

// Unser Thermometer dreht sich im Kreis

void loop(void) {
// Alle anwesenden Sensoren um Temperatur bitten
sensors.requestTemperatures();

// Wir nehmen den erstbesten
Serial.println(sensors.getTempCByIndex(0));

delay(1000); // und goennen uns eine Sekunde Pause
}

Wir lernen: Einige Arduino-Bibliotheken funktionieren auch für STM32-Boards. Aber: Speziell Bibliotheken mit direktem Hardwarezugriff oder Einsatz von AVR Inline-Assembler-Code können auf der Blue Pill nicht laufen. Zum Glück arbeitet die STM32duino-Welt kontinuierlich an der Integration von Bibliotheken.

Kommunikation mit der Aussenwelt

Von Natur aus, ist eine Blue Pill ist sehr schweigsam und besitzt keinen IC für WiFi oder Bluetooth. Abhilfe schaffen können Maker zum Beispiel mit dem ESP-01 aus der ESP8266-Familie. Eine Implementierung für den Zugriff auf ein ESP8266-Board im AT-Kommandomodus liefert Steve Strong (siehe hier[10]). Steve hat einen minimalistischen Webserver implementiert, um LEDs über einen Browser zu schalten oder deren Zustand abzufragen (Anm.: In einem vergangenen Beitrag[11] hatte ich das Zusammenspiel von Arduino mit ESP-01 im AT_Kommandomodus beschrieben).

Eine Integration von Websockets [12] stammt vom gleichen Autor.

Problem Child?

Leider haben die meisten Chargen der Blue Pill einen kleinen Fehler eingebaut. An D+ (siehe Abbildung) wäre ein 1.5 KΩ Pull-up-Widerstand notwendig. Stattdessen findet sich dort ein Widerstand mit 4.7 KΩ oder 10 KΩ. Hat der Widerstand die Aufschrift 103, so handelt es sich um einen Widerstand mit 10 KΩ, bei Code 472 indessen um einen 4.7 KΩ Widerstand. Der korrekte Code lautet aber 153 (= 1.5 * 103).

Das bleibt meistens ohne Folgen, oder es macht sich durch sporadische Probleme beim Sketch-Upload bemerkbar. Auf meinem iMac muss ich bei einigen Blue Pills öfters den Upload durchführen bis es klappt.

Wollen Maker das Problem lösen, müssen sie Hand anlegen. Entweder sie entfernen den fehlerhaften SMD-Widerstand und ersetzen ihn durch einen neuen. Oder sie verwenden die ästhetisch nicht ganz astreine Lösung aus folgender Abbildung:

http://amitesh-singh.github.io/stm32/2017/05/27/Overcoming-wrong-pullup-in-blue-pill.html
Um den Fehler auszumerzen, löten Sie den falschen Widerstand in einer Reflow-Station aus und bringen einen geeigneten Widerstand an. Alternativ können Sie das Problem auch so lösen wie in der Abbildung (Bild: http://amitesh-singh.github.io/stm32/2017/05/27/Overcoming-wrong-pullup-in-blue-pill.html)

Als reine Softwarelösung schlägt Amitesh Singh (von ihm stammt auch die obige Abbildung) vor[13], folgende Codesequenz am Anfang eines Programms einzubauen:

// Notwendig bei inkorrektem Pull-up-Widerstand an D+
// Ein Muss für chinesische Boards des Typs stm32f103c8t6, auch bekannt als "Blue Pill"
rcc_periph_clock_enable(RCC_GPIOA);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
gpio_clear(GPIOA, GPIO12);
msleep(5); // Pause

Das klingt zwar etwas nach Dieselabgas-Affäre, funktioniert aber tatsächlich.

Fazit

Eine Blue Pill bietet zu einem günstigen Preis sehr gute Leistung. Dank der Aktivitäten der STM32duino-Community lässt sie sich in der gewohnten Arduino IDE programmieren, wobei einige Bibliotheken funktionieren, aber nicht alle. Die Blue Pill ist nur eine Vertreterin der unterstützten STM32-Boards. Es gibt viele weitere, auf die der Beitrag aus Platzgründen nicht eingehen kann. Diese kommen in zukünftigen Postings zur Sprache, etwa das Maple-Board, das wie die Blue Pill aus der STM32F103-Familie stammt. Beim Entwickeln mit Blue Pills verlassen Programmierer ein wenig ihre Komfortzone, weil die Unterstützung für Arduino-Boards noch viel umfangreicher ist. Auf der anderen Seite bieten sich im STM32-Universum viele unterschiedliche Werkzeugketten an, die Debugging gut unterstützen, sich ebenfalls für Pros eignen, oder sogar die Generierung von Projekten erlauben wie STM32Cube.

Ein Eintauchen in die Welt der Blue Pill und ihrer Verwandten macht jedenfalls Spaß und erweitert den Horizont.


URL dieses Artikels:
http://www.heise.de/-4009580

Links in diesem Artikel:
[1] http://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf
[2] http://www.st.com/en/development-tools/flasher-stm32.html
[3] http://www.st.com/en/ecosystems/stm32cube.html?querycriteria=productId=SC2004
[4] http://www.openstm32.org/HomePage
[5] https://github.com/trebisky/stm32f103
[6] https://satoshinm.github.io/blog/171212_stm32_blue_pill_arm_development_board_first_look_bare_metal_programming.html
[7] http://www.stm32duino.com
[8] https://github.com/rogerclarkmelbourne/Arduino_STM32
[9] https://www.heise.de/developer/artikel/Lauschen-mit-Sensoren-3217195.html
[10] https://github.com/stevstrong/STM32_ESP01_WebServer
[11] https://www.heise.de/developer/artikel/Ueberraschungsei-fuer-Wetterfroesche-dank-BME680-ESP8266-Arduino-ThingSpeak-3979158.html
[12] http://www.stm32duino.com/viewtopic.php?f=19&amp;t=3281
[13] http://amitesh-singh.github.io/stm32/2017/05/27/Overcoming-wrong-pullup-in-blue-pill.html

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 03. April 2018 um 10:19

Blue Pill - STM32 ARM Cortex M3 Boards

Von heise online

zurück zum Artikel

Im Arduino-Universum existieren von einigen Herstellern Arduino-kompatible Boards, die mit anderen Prozessoren als denen aus der ATMEL-Microprozessorfamile aufwarten. Teensy, ESP8266 und ESP32 haben wir bereits kennengelernt. Von STMicroelectronics gibt es das Board STM32F103C8, das seine Anhänger Blue Pill nennen - ein Board mit ausgezeichnetem Preis-/Leistungsverhältnis.

Welcome, on Board

Warum die Blue Pill so heißt wie sie heißt, lässt sich dem folgenden Profilbild entnehmen:

Der Microcontroller STM32F103C8, oft nur unter seinem Kosenamen Blue Pill bekannt, liefert hohe Leistung für wenig Geld
Der Microcontroller STM32F103C8, oft nur unter seinem Kosenamen Blue Pill bekannt, liefert hohe Leistung für wenig Geld (Bild: http://wiki.stm32duino.com)

Mit einer 32Bit ARM-Cortex-M3-Architektur und einer Taktfrequenz von 72 MHz steckt die Blue Pill einen Arduino auf Basis des ATMega328P performanzmäßig locker in die Tasche. 64 KB (manchmal auch 128 KB) Flashspeicher und dazu 20 KB RAM bieten genügend Reserven für viele Aufgabenstellungen. Zudem beinhaltet das Board eine mit 32 MHz getaktete Echtzeituhr (RTC). Im Normalbetrieb unterstützt der Mikrocontroller ein Logiklevel von 3.3V. Es sind zwar auch 5V möglich, wobei einige, aber nicht alle Pins 5V vertragen.

Für eine Blue Pill ist beim Dealer ein Obolus zwischen 2 und 5 Euro zu entrichten. Wie immer gilt: Je kleiner der Preis, desto näher liegt der Händler an China.

Das Board verfügt über mehrere serielle Ports, und über mehrere SPI- und I2C-Busanschlüsse (siehe nachfolgende Abbildung des Pin-Layouts). Ein ADC mit 12-Bit-Auflösung lässt die genauere Messwerterfassung von Sensoren zu.

Und natürlich darf eine essenzielle Information nicht fehlen: die eingebaute LED der Blue Pill liegt am Pin PC13.

Die Pinbelegung zeigt, dass die Blue Pill einige nützliche Features besitzt, unter anderem mehrere serielle Ports, CAN- SPI- und I2C-Anschlüsse
Die Pinbelegung zeigt, dass die Blue Pill einige nützliche Features besitzt, unter anderem mehrere serielle Ports, CAN- SPI- und I2C-Anschlüsse

Mehr Details erfährt der Entwickler in einem von STMicroelectronics bereitgestellten Dokument[1].

Hinweis

Beim Performanzvergleich zwischen Cortex-M3 und ATMega328P lauern Fallstricke. Ein Beispiel gefällig: In der Arduino IDE gibt es zwar double und float als Datentypen. Beide sind auf Arduino-Boards aber identisch und umfassen jeweils 32 Bit. Auf einem Cortex-M3-Board wie der Blue Pill sind Werte des Typs double aber 64-Bit breit, haben also doppelte Größe. Beim Benchmarking ist daher wichtig, nicht Äpfel mit Birnen zu vergleichen.

Entwicklungshilfen

In dieser Folge konzentriere ich mich darauf, wie sich das Board mit Hilfe der Arduino IDE programmieren lässt. Allerdings ist das nur eine der Möglichkeiten. Die meisten anderen Möglichkeiten für den Entwickler sind teilweise besser geeignet - zumindest für Pros. Leider habe ich an dieser Stelle nicht die Möglichkeit, diese anzusprechen. Wenigstens sollen einige dieser Optionen zur Sprache kommen:

  • Mittels des STM32 Flash Tools[2] können Entwickler ihren Code beispielsweise mit Microsoft Visual Studio erstellen und das Ergebnis über den UART auf das Board laden.
  • Das umfangreiche Werkzeug STM32CubeMX[3] erlaubt die Codegenerierung für Projekte und entsprechende Werkzeugketten, ebenso die Erzeugung von Code für komplexere Embedded-Aufgaben mittels grafischer Wizards. Dabei lassen sich alle möglichen Bibliotheken aus dem STM32Cube importieren.
  • Über ST-Link V2, einen In-Circuit Debugger and Programmer, schließen Entwickler die Blue Pill an ihren Rechner an und nutzen zur Programmierung z.B. die kostenlose OpenSTM32[4] System Workbench auf Basis von Eclipse. Wer ein Nucleo-64-Board von STM besitzt, kann dessen ST-Link-Schnittstelle zum Programmieren benutzen.
  • Natürlich bevorzugen einige Entwickler Bare Metal Programming. Wie das geht, zeigt trebisky auf seiner Github-Seite[5].

Generell zu empfehlen ist auch die Blog-Seite[6], die über mehrere dieser Programmieroptionen schreibt.

Integration in die Arduino IDE

Zum Glück gibt es eine große Community namens STM32duino, die sich um das Integrieren von STM32-Boards in das Arduino-Ökosystem kümmert. Viele Informationen, Tipps und Tricks sind auf deren Website[7] zu finden. Ein Besuch dieser Webseiten ist daher sehr zu empfehlen.

Doch nun in medias res. Um Unterstützung für die Blue Pill in die Arduino IDE zu integrieren, bedarf es mehrere Schritte. Dazu nötig ist mangels ST-Link-Programmer eine serielle Verbindung zu einem FTDI-Board oder einem anderen UART-USB-to-TTL-Adapter.

Schritt 1: Blue Pill mit UART-USB-to-TTL-Adapter verbinden

Zunächst sind die notwendigen Verbindungen zwischen Blue Pill und dem verwendeten UART-USB-to-TTL-Adapter zu etablieren (siehe Abbildung). Nach dem Anschluss des Ganzen per USB an den Computer blinkt normalerweise die LED an PC13, weil der Blink-Sketch bei der Produktion zu Testzwecken aufgespielt wurde.

Was genau zu tun ist:

  • Die Stromversorgung des FTDI-Adapter (Vcc, GND) verbinden wir mit 3.3V und GND an der Blue Pill.
  • An Pin A9 liegt der TX-Ausgang der Blue Pill und ist mit dem RX-Eingang des Adapters zu verdrahten.
  • Pin A10 der Blue Pill entspricht dem RX-Eingang und ist entsprechend mit dem TX-Ausgang des Adapters zu verbinden.
Verbindung von Blue Pill und UART-Usb-to-TTL-Adapter
Verbindung von Blue Pill und UART-Usb-to-TTL-Adapter

Schritt 2: Board-Manager für Arduino SAM Boards laden

Im nächsten Schritt gehen Sie über Tools > Boards > Boards Manager, suchen nach Arduino SAM Boards (ARM Cortex-M3) und installieren den entsprechenden Board-Manager.

Im zweiten Schritt ist die Installation des Boardmanagers für ARM Cortex M3 Boards notwendig
Im zweiten Schritt ist die Installation des Boardmanagers für ARM Cortex M3 Boards notwendig

Schritt 3: STM32duino Coreinstallieren

Roger Clark ist Master des Githubs für STM32-basierte Arduino Cores. Laden Sie sich über dessen Github-Seite[8] das gesamte Paket als ZIP-Archiv herunter. Damit lassen sich Blue Pills in der Arduino IDE wie native Arduino Boards programmieren.

Auf der Github-Seite von STM32DUINO ist das Zip-Archiv verfügbar
Auf der Github-Seite von STM32DUINO ist das Zip-Archiv verfügbar

Das Archiv gilt es zu entpacken und das daraus resultierende Verzeichnis Arduino_STM32 in das Arduino IDE Sketchbook Verzeichnis auf den Computer zu kopieren, zum Beispiel

  • unter Windows als Unterverzeichnis von My Documents\Arduino\Hardware
  • unter macOS als Unterverzeichnis von ~/Documents/Arduino/hardware

Sollte das Hardware-Verzeichnis noch nicht existieren, muss es angelegt werden. Danach verlassen Sie die Arduino IDE und starten die IDE erneut. Jetzt können Sie nicht nur Blue Pill, sondern auch andere Boards von STM unter der Arduino IDE nutzen.

Schritt 4: Blue Pill Einstellungen setzen

Gehen Sie in der Arduino IDE unter Tools und konfigurieren Sie das entsprechende Board (siehe links oben in der Abbildung)..

Für die Blue Pill ist das die Generic STM32F103C8 series die richtige Wahl als Board
Für die Blue Pill ist das die Generic STM32F103C8 series die richtige Wahl als Board

Unter Menüpunkt Variant sollten Sie einstellen: STM32F103C8 (20k RAM. 64k Flash).

Danach als Upload method: "Serial" (es sei denn, Sie verwenden eine andere Variante des Programmers wie etwa ST-LINK).

Unter Port spezifizieren Sie den von dem UART-USB-to-TTL Adapter verwendeten seriellen Port. Nutzen Sie etwas anderes als einen FTDI-basierten Adapter, ist zuvor eventuell das zusätzliche Installieren eines für Ihren Adapter bestimmten USB-Treibers notwendig.

Schritt 5: Testsketch programmieren

Im Menüpfad File > Examples > A_STM32-Examples > Digital können Sie als Testprogramm beispielsweise Blink wählen. Port PB1 ändern Sie dabei in PC13. Oder Sie schreiben einfach einen eigenen Testsketch. Mein simpler Sketch für das LED-Blinken sieht wie folgt aus:

void setup() {
pinMode(PC13, OUTPUT); // OnBoard-LED liegt an PC13
Serial.begin(9600); // Ausgabe am seriellen Monitor
}

void loop() {
digitalWrite(PC13, !digitalRead(PC13)); // LED invertieren
Serial.println(digitalRead(PC13) ? "low" : "high"); // -> ser. Monitor
delay(1000); // Pause einlegen
}

Bevor sich der Sketch auf die Blue Pill laden lässt, ist das Setzen des Blue Pill in den Programmiermodus wichtig. Zu diesem Zweck bewegen Sie den oberen gelben Jumper (BOOT0) von Position 0 auf 1 (im nachfolgenden Bild von links nach rechts), und drücken anschließend die RESET-Taste. Der untere Jumper BOOT1 bleibt dabei stets unverändert.

Den BOOT1-Jumper können Sie übrigens für eigene Anwendungen nutzen. Er hat sonst keine andere Funktion.

Um einen Sketch hochlasden zu können, muss der BOOT0-Jumper (oben) auf 1 gestellt, und anschließend ein Reset durchgeführt werden.
Um einen Sketch hochladen zu können, muss der BOOT0-Jumper (oben) auf 1 gestellt, und anschließend ein Reset durchgeführt werden.

Nun kann die Arduino IDE den kompilierten Sketch auf die Blue Pill laden. Hat das geklappt, passiert folgendes: Die Onboard-LED blinkt. Im seriellen Monitor sehen Sie zeilenweise eine Folge von "low" und "high"-Nachrichten.

Soll der Sketch nach einer Änderung neu auf das Board geladen werden und ist der BOOT0-Jumper immer noch auf Stellung 1 positioniert, genügt ein Reset vor dem Sketch-Upload. Wollen Sie hingegen ein Überschreiben des Sketches verhindern, setzen Sie diesen Jumper auf Position 0 zurück.

Port Mapping

Um die in der Arduino IDE verwendbaren Port-Namen zu kennen, genügt ein Blick auf die Implementierung des STM32duino Core, genauer gesagt auf die Headerdatei board.h:

...Header board.h ....

#define BOARD_NR_USARTS 3
#define BOARD_USART1_TX_PIN PA9
#define BOARD_USART1_RX_PIN PA10
#define BOARD_USART2_TX_PIN PA2
#define BOARD_USART2_RX_PIN PA3
#define BOARD_USART3_TX_PIN PB10
#define BOARD_USART3_RX_PIN PB11

#define BOARD_NR_SPI 2
#define BOARD_SPI1_NSS_PIN PA4
#define BOARD_SPI1_MOSI_PIN PA7
#define BOARD_SPI1_MISO_PIN PA6
#define BOARD_SPI1_SCK_PIN PA5

#define BOARD_SPI2_NSS_PIN PB12
#define BOARD_SPI2_MOSI_PIN PB15
#define BOARD_SPI2_MISO_PIN PB14
#define BOARD_SPI2_SCK_PIN PB13

#define BOARD_NR_GPIO_PINS 35
#define BOARD_NR_PWM_PINS 12
#define BOARD_NR_ADC_PINS 9
#define BOARD_NR_USED_PINS 4

#define BOARD_JTMS_SWDIO_PIN 22
#define BOARD_JTCK_SWCLK_PIN 21
#define BOARD_JTDI_PIN 20
#define BOARD_JTDO_PIN 19
#define BOARD_NJTRST_PIN 18

#define BOARD_USB_DISC_DEV GPIOB
#define BOARD_USB_DISC_BIT 10

// Note this needs to match with the PIN_MAP array in board.cpp
enum {
PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, PA11, PA12, PA13,PA14,PA15,
PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11, PB12, PB13,PB14,PB15,
PC13, PC14,PC15
};

...

Beim Entwickeln in der Arduino IDE können Programmierer die obigen Bezeichner nutzen.

Demobeispiel

Jetzt soll ein etwas komplexerer Sketch demonstrieren, dass sich durchaus für die Blue Pill Bibliotheken in der Arduino IDE so nutzen lassen als hätten wir ein natives Arduino-Board vor uns. Im Beispiel ist ein Temperatursensor des Typs Dallas DS18B20 angeschlossen. Zu dessen Nutzung hat Maxim (der heutige Name des Herstellers) den OneWire-Bus eingeführt. Den OneWire-Bus und den Sensor hatte ich bereits in einem früheren Beitrag[9] illustriert.

Das Schaltbild erweitert sich wie folgt:

Blue Pill und DS18B20 gehen gemeinsame Wege
Blue Pill und DS18B20 gehen gemeinsame Wege

Der Sensor (links oben in der Schaltung) ist über Pin PA2 angeschlossen.

Der Sketch ist eher einfach gestrickt. Er soll einfach in jedem Zyklus den Sensorwert des DS18B20 erfassen und am seriellen Monitor ausgeben:

//************************************************
// Blue Pill plus DS18B20 Dallas Temperatursensor
// Demonstration zur Verwendung der Bibliotheken
// fuer Blue Pill in der Arduino IDE
//************************************************

// Zutaten: 1-Wire Protokoll und Sensor-Bibliothek
#include
#include

// Der Bus haengt an Port PA2 des STM32F103C Boards
#define ONE_WIRE_BUS PA2

// 1-Wire-Protokoll initialisieren
OneWire oneWire(ONE_WIRE_BUS);

// ... und Referenz übergeben
DallasTemperature sensors(&oneWire);

// Generelles Setup von seriellem Monitor und der
// Sensor-Bibliothek

void setup(void)
{
Serial.begin(9600); // seriellen Monitor starten
Serial.println("Demo des DS18B20 Sensors an der Blue Pill");

// Bibliothek initialisieren
sensors.begin();
}

// Unser Thermometer dreht sich im Kreis

void loop(void) {
// Alle anwesenden Sensoren um Temperatur bitten
sensors.requestTemperatures();

// Wir nehmen den erstbesten
Serial.println(sensors.getTempCByIndex(0));

delay(1000); // und goennen uns eine Sekunde Pause
}

Wir lernen: Einige Arduino-Bibliotheken funktionieren auch für STM32-Boards. Aber: Speziell Bibliotheken mit direktem Hardwarezugriff oder Einsatz von AVR Inline-Assembler-Code können auf der Blue Pill nicht laufen. Zum Gluck arbeitet die STM32duino-Welt kontinuierlich an der Integration von Bibliotheken.

Kommunikation mit der Aussenwelt

Von Natur aus, ist eine Blue Pill ist sehr schweigsam und besitzt keinen IC für WiFi oder Bluetooth. Abhilfe schaffen können Maker zum Beispiel mit dem ESP-01 aus der ESP8266-Familie. Eine Implementierung für den Zugriff auf ein ESP8266-Board im AT-Kommandomodus liefert Steve Strong(siehe hier[10]). Steve hat einen minimalistischen Webserver implementiert, um LEDs über einen Browser zu schalten oder deren Zustand abzufragen. In einem vergangenen Beitrag[11] hatte ich das Zusammenspiel von Arduino mit ESP-01 im AT_Kommandomodus erläutert.

Eine Integration von Websockets [12] stammt vom gleichen Autor.

Problem Child?

Leider haben die meisten Chargen der Blue Pill einen kleinen Fehler eingebaut. An D+ (siehe Abbildung) wäre ein 1.5 KΩ Pull-up-Widerstand notwendig. Stattdessen findet sich dort ein Widerstand mit 4.7 KΩ oder 10 KΩ. Hat der Widerstand die Aufschrift 103, so handelt es sich um einen Widerstand mit 10 KΩ, bei Code 472 indessen um einen 4.7 KΩ Widerstand. Der korrekte Code lautet aber 152 (= 1.5 * 102).

Das bleibt meistens ohne Folgen, oder es macht sich durch sporadische Probleme beim Sketch-Upload bemerkbar. Auf meinem iMac muss ich bei einigen Blue Pills öfters den Upload durchführen bis es klappt.

Wollen Maker das Problem lösen, müssen sie Hand anlegen. Entweder sie entfernen den fehlerhaften SMD-Widerstand und ersetzen ihn durch einen neuen. Oder sie verwenden die ästhetisch nicht ganz astreine Lösung aus folgender Abbildung:

http://amitesh-singh.github.io/stm32/2017/05/27/Overcoming-wrong-pullup-in-blue-pill.html
Um den Fehler auszumerzen, löten Sie den falschen Widerstand in einer Reflow-Station aus und bringen einen geeigneten Widerstand an. Alternativ können Sie das Problem auch so lösen wie in der Abbildung (Bild: http://amitesh-singh.github.io/stm32/2017/05/27/Overcoming-wrong-pullup-in-blue-pill.html)

Als reine Softwarelösung schlägt Amitesh Singh (von ihm stammt auch die obige Abbildung) vor[13], folgende Codesequenz am Anfang eines Programms einzubauen:

// Notwendig bei inkorrektem Pull-up-Widerstand an D+
// Ein Muss für chinesische Boards des Typs stm32f103c8t6, auch bekannt als "Blue Pill"
rcc_periph_clock_enable(RCC_GPIOA);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
gpio_clear(GPIOA, GPIO12);
msleep(5); // Pause

Das klingt zwar etwas nach Dieselabgas-Affäre, funktioniert aber tatsächlich.

Fazit

Eine Blue Pill bietet zu einem günstigen Preis sehr gute Leistung. Dank der Aktivitäten der STM32duino-Community lässt sie sich in der gewohnten Arduino IDE programmieren, wobei einige Bibliotheken funktionieren, aber nicht alle. Die Blue Pill ist nur eine Vertreterin der unterstützten STM32-Boards. Es gibt viele weitere, auf die der Beitrag aus Platzgründen nicht eingehen kann. Diese kommen in zukünftigen Postings zur Sprache, etwa das Maple-Board, das wie die Blue Pill aus der STM32F103-Familie stammt. Beim Entwickeln mit Blue Pills verlassen Programmierer ein wenig ihre Komfortzone, weil die Unterstützung für Arduino-Boards noch viel umfangreicher ist. Auf der anderen Seite bieten sich im STM32-Universum viele unterschiedliche Werkzeugketten an, die Debugging gut unterstützen, sich ebenfalls für Pros eignen, oder sogar die Generierung von Projekten erlauben wie STM32Cube.

Ein Eintauchen in die Welt der Blue Pill und ihrer Verwandten macht jedenfalls Spaß und erweitert den Horizont.


URL dieses Artikels:
http://www.heise.de/-4009580

Links in diesem Artikel:
[1] http://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf
[2] http://www.st.com/en/development-tools/flasher-stm32.html
[3] http://www.st.com/en/ecosystems/stm32cube.html?querycriteria=productId=SC2004
[4] http://www.openstm32.org/HomePage
[5] https://github.com/trebisky/stm32f103
[6] https://satoshinm.github.io/blog/171212_stm32_blue_pill_arm_development_board_first_look_bare_metal_programming.html
[7] http://www.stm32duino.com
[8] https://github.com/rogerclarkmelbourne/Arduino_STM32
[9] https://www.heise.de/developer/artikel/Lauschen-mit-Sensoren-3217195.html
[10] https://github.com/stevstrong/STM32_ESP01_WebServer
[11] https://www.heise.de/developer/artikel/Ueberraschungsei-fuer-Wetterfroesche-dank-BME680-ESP8266-Arduino-ThingSpeak-3979158.html
[12] http://www.stm32duino.com/viewtopic.php?f=19&amp;t=3281
[13] http://amitesh-singh.github.io/stm32/2017/05/27/Overcoming-wrong-pullup-in-blue-pill.html

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 03. April 2018 um 10:19

Welt-Spar-Tag

Von heise online

zurück zum Artikel

Wer IoT-Geräte in freier Wildbahn, also an Orten ohne Steckdose, betreiben möchte, stößt bald auf ein Problem. Ohne entsprechende Vorkehrungen saugen Schaltungen mit Mikrocontrollern in kürzester Zeit Batterien oder Akkus leer. Um möglichst sparsam mit der verfügbaren Energie umzugehen, gibt es einige Möglichkeiten.

Tipps und Tricks

Dieses Posting entstand deshalb, weil ein Leserkommentar dazu angeregt hat. Allerdings gilt: Auch der Autor dieses Blogs hat die Weisheit nicht mit Löffeln gefressen. Daher betrachten Sie bitte die folgende Liste lediglich als unvollständige Sammlung. Ihre Tipps und Erfahrungen sind daher willkommen, um diese Liste auszubauen.

Das Problem

Bereits im Leerlauf mit dem BareMinimum-Beispiels-Sketch aus der Arduino IDE verbraucht ein Arduino Uno rund 15mA. Verwendet die Schaltung einen 9V-Block aus Zink-Kohle als Energiequelle, so hat die Batterie nach rund 22 Stunden das Ende ihrer Kapazität erreicht. Fügt jemand der Schaltung noch einen 220Ω Widerstand und eine LED hinzu, reduziert sich die ohnehin sehr geringe Laufzeit nochmals. Zusatzhardware wie ein Kohlenmonoxid-Gassensor oder eine Wetterstation könnte auch diese eingeschränkte Batterie-Lebensdauer verringern. Ganz zu schweigen von Situationen, in denen Kommunikationstechnologien wie WiFi, Bluetooth oder LoRa ins Spiel kommen. Gerade bei autark arbeitenden oder mobilen IoT-Geräten wiegt diese Herausforderung besonders schwer, weil die erwarteten Batterie-Kapazitäten oft für Tage, Monate oder sogar Jahre reichen müssen. Bei stationären Geräten mit Netzanschluss erwarten Nutzer mittlerweile einen energiesparenden Betrieb. Was nun, Herr und Frau Maker?

"Wer misst, misst Mist" - was nicht immer richtig ist

Vorweg möchte ich kurz auf das Thema Werkzeuge für Maker zu sprechen kommen. Ohne Diagnosewerkzeug lassen sich Schaltungsfehler oft nur schwer aufspüren.

Um dem Energieverbrauch auf dem Grund zu gehen, empfiehlt sich der Einsatz eines guten Multimeters. Damit können Maker gezielt überprüfen, an welchen Stellen welche Energieverbräuche entstehen. Es gibt hierfür recht preisgünstige Messtechnik (etwa das sehr gut bewertete Ragu 17B für 29,99 Euro[1]), aber selbst für ernsthaftere Hobbyisten sei auf lange Sicht Qualitätshardware empfohlen. Diese messen genauer, reagieren schneller, und arbeiten zuverlässiger. Die Geräte von Fluke gehören sicher zum Nonplusultra, was Preis und Qualität betrifft, lassen sich aber schon in kleineren Varianten für unter 200 Euro erwerben. Etwa ein Fluke Multimeter 113 für um die 120 Euro oder ein 117 für unter 200 Euro.

amazon.com
Ein Fluke 117 Multimeter geht schon für unter 200 Euro über den Ladentisch (Bild: amazon.com)

Ein Multimeter ist selbstredend nicht nur sinnvoll, um den Energiekillern auf die Spur zu kommen, sondern auch für die Fehlersuche oder Diagnose bei Schaltungen.

DiY für Messtechnik

Der konsequente Maker baut sogar seine Messgeräte selbst, wobei hier natürlich die Geschichte von Huhn und Ei in den Sinn kommt.

  • In seiner Instructable-Anleitung [2]stellt Milen den Bau eines Arduino-Multimeter-Shields vor
  • Das Design eines Strommessers findet sich zum Beispiel auf dieser Seite[3]
  • Mittels Sensor-Breakout-Boards auf Basis von ICs wie MAX471, INA219, ACS712 lassen sich Strommessungen in Schaltungen durchführen
  • Auch Voltmeter, Ohmmeter und Arduino-Schaltungen zur Erfassung weiterer physikalischer Größen finden sich im Internet zuhauf

Natürlich gibt es einige andere Geräte, die in Zukunft noch im Blog zur Sprache kommen. (Logik-Analysatoren für die Diagnose digitaler Logik - etwa zur Buskommunikation mit SPI, I2C, PWM - hatte ich bereits in einem früheren Beitrag[4] vorgestellt).

Zur Messung des Energieverbrauchs verwendet der Maker eine 9V-Blockbatterie oder eine andere Konfiguration. Zu diesem Zweck ist ein Multimeter (Amperemeter) mit der zu überprüfenden Elektronik in Serie zu schalten.

Suchen Sie den Punkt im Schaltkreis, an dem Sie die Stromstärke messen möchten. An diesem Punkt unterbrechen Sie den Schaltkreis und verbinden ein Ende mit dem COM-Port des Multimeters und das andere Ende mit dem mA/A-Port des Multimeters. Das Multimeter fungiert nun als Teil der Leitung, sodass der Stromkreis wieder geschlossen ist. Bei Spannungsmessungen schalten Sie hingegen das Multimeter parallel zum gemessenen Teil der Schaltung.

Insgesamt ergibt sich also folgendes Bild:

Serienschaltung von Multimeter und dem zu messenden Schaltkreis
Serienschaltung von Multimeter und dem zu messenden Schaltkreis

Die angezeigten mA-Werte zeigen den zu einem Zeitpunkt benötigten Energiebedarf der Schaltung. Die Spannung am Arduino-Board beträgt bekanntlich stets 5V (beziehungsweise 3.3V). Und die Leistung beträgt immer P = U * I = 5V * I.

Mit diesem Aufbau ist folglich die (Un-)Wirksamkeit der diversen Power-Save-Maßnahmen überprüfbar.

Übrigens lässt sich der Arduino mit Hilfe eines Spannungsteilers mit Widerständen sogar dazu verwenden, um seinen eigenen Stromverbrauch per Selbstreflektion zu ermitteln. Sie sind daran interessiert? Dann empfehle ich das entsprechende YouTube-Video von Matteo Corti[5].

MCU- und IC-Overkill vermeiden

Einen Arduino Mega oder einen Raspberry Pi einzusetzen, nur um regelmäßig einen schlichten Temperatursensor auszulesen, heißt mit Kanonen auf Spatzen schießen. Je leistungsfähiger der Mikrocontroller und je umfangreicher die auf dem Board verbauten Komponenten, desto höher der Verbrauch.

Schließlich konsumiert auch jeder nicht benötigte IC in einer Schaltung oder auf einem Mikrocontroller-Board Energie. Ein gutes Beispiel ist der UART-USB-TTL Adapter, der ständig rund 10 mA "verbrennt". Nur als Beispielsrechnung: Einen 9V-Block aus Alkali-Mangan mit 600 mAh würde allein der UART in maximal 60 Stunden völlig entleeren.

Arduino-MCUs wie Pro Mini besitzen keinen UART. Ihre Programmierung erfolgt über einen temporär angeschlossenen externen UART-USB-TTL-Adapter oder über eine Programmer-Hardware. Erwähnenswert an dieser Stelle ist, dass der Arduino Pro Mini im Prinzip ein um den UART-USB-TTL-Adapter abgespeckter Arduino Nano ist.

Zu den Stromfressern gehört des Weiteren die Power-on-LED, die mit rund 4 mA zu Buche schlägt. Eine drastische Massnahme besteht daher im Auslöten dieser LED beziehungsweise ihrem Aushebeln mittels Zange.

Auf der anderen Seite ver(sch)wenden lineare Spannungsregulatoren ebenfalls Energie und zwar abhängig davon, wie groß der Unterschied zwischen Eingangsspannung und Ausgangsspannung ist. Je höher dieser Wert, desto mehr Energie kommt durch Wärmeverluste abhanden. Die Formel hierfür lautet:

P = (Vout-Vin) * I.

Hier lässt sich entweder der Regulator ganz entfernen, und/oder ein effizienterer Regulator verwenden. Wer den Regulator entfernt, muss aber dafür sorgen, dass genau die notwendige Betriebsspannung (5V oder bei einigen Boards 3.3V) in Vin anliegt. Daher ist es zum Teil praktikabler, den internen Regulator zu deaktivieren und durch einen sparsamen, externen Regulator zu ersetzen. Experimentierfreudige Zeitgenossen haben hin und wieder den internen linearen Regulator auf dem Arduino-Board ausgelötet und durch einen effizienteren Regulator ersetzt. Es gibt zum Glück Arduino-Boards wie das Sparkfun Pro Mini, die das Deaktivieren des internen Regulators per Jumper erlauben.

Der Blogartikel [6]empfiehlt zum Beispiel Regulatoren von Microchip wie MCP1700 und MCP1703, die es jeweils in Varianten für 3.3V und 5V zu kaufen gibt.

Richtigen Logik Level und richtige Frequenz wählen

Der Energieverbrauch steigt quadratisch mit der Spannung und linear mit der Frequenz. Kleinere Logik-Level reduzieren den Energieverbrauch, etwa Verwenden von 3.3V statt 5V. Zur Erinnerung, die Formel für die Leistung lautet

P = U2 / R.

Dann aber müssen Mikrocontroller wie der Atmel 328P herunter-getaktet werden. Laut Datenblatt verträgt der Prozessor bei 3.3V Versorgungsspannung keine 16MHz, weshalb Boards wie das Arduino Pro Mini im 3.3V-Betrieb unter 8 MHz laufen.

Der optimale Logik-Level hängt aber natürlich auch von den benützten Sensoren, Aktuatoren, Breakout-Boards oder Shields ab. Benötigen diese 5V, macht es eventuell nur wenig Sinn, mit einem 3.3V-Mikrocontroller-Board zu arbeiten. Und einige Bibliotheken könnten bei geänderter Taktfrequenz nicht oder nur eingeschränkt funktionieren.

Solarzellen

In Zeiten der Nachhaltigkeit kann das Thema alternative Energien natürlich nicht fehlen. Nur mit einer Solarzelle lässt sich eine Schaltung allerdings nicht betreiben, weil normalerweise tagsüber gerade einmal zwischen 10.00h und 14:00h optimale Sonneneinstrahlung herrscht. Die Solarzelle sollte also dazu dienen, NiMH-Akkus aufzuladen, von denen sich wiederum die Schaltung speist. Beispielsweise lässt sich ein 2 x 1.2V AA Doppel-Akkupack (gesamt 2.4V mit NiMh-Akkus) in Kombination mit einem Baustein (Voltage Booster, zum Beispiel XL6009) nutzen, der die Spannung auf die von den meisten Arduino-Boards benötigten 5V erhöht. Als Faustregel gilt: Die Spannung des Solarpanels muss ungefähr anderthalb (bis doppelt) so hoch sein. Im Falle eines Arduino Pro Mini mit 3.3V Spannung bietet sich ein >= 6V-Panel an. Beträgt die Kapazität der Akkus 1300mAh, sollte ihr Aufladen maximal mit einem Zehntel erfolgen (= 130 mA), aber mit 100 mA im Idealfall, sodass die Ladezeit rund 10-16 Stunden beträgt.

Mehr ist nicht immer besser: Je höher die Ladestrom, desto schneller zwar das Laden, aber auch desto geringer die Lebenszeit der Akkus. Empfehlenswert ist der Einsatz einer Diode (zum Beispiel Typ LN4148) zwischen positivem Terminal von Solarpanel und positivem Terminal des NiMh-Batteriepacks, wobei der positive Port des Batteriepacks mit der Plus-Seite der Diode verbunden ist, und das negative Ende der Diode mit dem positiven Potenzial des Batteriepacks. Negative Ports von Solarpanel und Batteriepack sind hingegen direkt verbunden. Für NiMh-Akkus gestaltet sich die Schaltung also recht pflegeleicht.

Wer stattdessen LiIon-Akkus wie ein 18650 nutzen möchte, hat ein bisschen mehr Aufwand, weil dafür ein LiIon-Ladecontroller benötigt wird, zum Beispiel ein TP4056. Das Überschreiten oder Unterschreiten gewisser Ladungsschwellwerte kann die Batterie zerstören, und nicht nur die.

Mehr Details zum Anschluss von Solarpanels liefert folgender guter Beitrag auf instructables[7].

Ewig schläft das Murmeltier

Schon aus den bisherigen Ausführungen ergibt sich die Schlussfolgerung, dass es Energieverbrauch für nicht benötigte Komponenten tunlichst zu vermeiden gilt. Dafür gibt es bei Embedded Controllern die Möglichkeit der Schlafmodi, d.h. die Komponenten laufen nur zu bestimmten Zeitpunkten. Ausserhalb dieser Zeitpunkte befinden sie sich in einem Schlafmodus, der weniger Energie benötigt. Nicht verwendete Komponenten wie ADC verbrauchen aber auch unter Umständen in einem Schlafmodus viel Strom, und lassen sich bei vielen Mikrocontrollern daher auch komplett abschalten.

Ein paar Worte speziell zu Arduino-Boards, bei denen die meisten einen ATMega328P oder einen ATMega168P beinhalten: Laut Datenblatt des ATMega328P[8] (Kapitel 9) sind besonders folgende Komponenten Stromverbrauch-Kandidaten:

  • Der ADC (Analog-Digital Converter) sollte generell oder vor dem Schlafmodus deaktiviert werden. ADCs verbrauchen sonst eine gehörige Portion Strom.
  • Der Analog Comparator vergleicht positive Spannung an einem Pin mit der negativen Spannung an einem anderen Pin und setzt entsprechende Registerwerte oder kann einen Interrupt auslösen. Bis auf Idle-Mode und Noise-Reduction-Mode legt der Prozessor den Analog Comparator in allen Schlafmodi automatisch schlafen. In den vorgenannten beiden Modi empfiehlt es sich, falls möglich, den Baustein manuell zu deaktivieren.
  • Der Brown-out-Detector (BoD) sorgt für ein Herunterfahren des Systems, sobald die Ist-Spannung die Soll-Spannung für einen bestimmten Zeitraum unterschreitet. Der BoD hat auch in diversen Schlafmodi großen Stromhunger, weshalb es eine gute Idee ist, ihn zu deaktivieren.
  • Von der Internal-Voltage-Reference sind BoD, ADC, und Analog Comparator abhängig. Deaktiviert der Entwickler diese Bausteine, so bleibt auch die Internal-Voltage-Reference außer Betrieb
  • Im Schlafmodus sollten die Port Pins ebenfalls nur minimale Energie verbrauchen. Gerade analoge Pins haben Umständen großen Appetit. Das lässt sich zum Beispiel bewerkstelligen, indem der Sketch alle nicht benötigten digitalen Pins im Set-up als Output-Pins deklariert und/oder Pull-Down-Widerstände aktiviert.
  • Das On-Chip-Debug-System muss nur im Bedarfsfall aktiv sein, weil es im Betrieb substanziellen Energieverbrauch aufweist.

Der Watchdog Timer (WDT) hingegen darf im Normalfall nicht deaktiviert werden, auch wenn er einige wenige (Bruchteile von) mA verspeist. Ihn benötigt die MCU als externen Wecker, um den Schlafmodus aufzuheben. Allerdings lässt der WDT maximal 8 Sekunden (Tief-)Schlaf zu, weshalb er bei längeren Schlafzeiten mehrfach hintereinander zu nutzen ist.

Interrupts wie Interrupt 0 (Arduino-Port 2) oder Interrupt 1 (Arduino-Port 3) heben den Schlafmodus ebenfalls auf. Sie lassen sich durch externe Ereignisse triggern, etwa dem Betätigen eines an diesen Eingängen anliegenden Push-Buttons oder einer RTC-Uhr. Das macht Sinn, wenn das Gerät ohnehin nur bei bestimmten externen Ereignissen loslaufen sollte, etwa bei Benutzerinteraktion

Der ATMega328P besitzt einige Fuses und Register, die das Verhalten und den Energieverbrauch in den diversen Schlafmodi steuern. An dieser Stelle habe ich nicht genug Raum, um auf Fuses einzugehen. Jedenfalls ist bei Nutzung derselben zur Konfiguration des Prozessors Vorsicht die Mutter der Porzellankiste. Bei einem Fehler ist der Arduino sonst gegebenenfalls nicht mehr oder nur mit großem Aufwand in Betrieb zu nehmen.

Auch das Schreiben von Register-Bit-Manipulationen bei Registern und Inline-Assemblerinstruktionen zum Initialisieren der Schlafmodi gestaltet sich eher mühevoll und fehlerträchtig. Wer sich trotzdem dafür interessiert und dabei viel über Schlafmodi der AVR-Prozessorfamilie lernen will, sei auf das exzellente, englischsprachige YouTube-Video von Kevin Darrah[9] verwiesen.

Rocket Scream LowPower Bibliothek

Statt sich mühsam und systemnah mit dem Sleep-Modi auseinanderzusetzen, empfiehlt sich die sehr gute Low-Power-Bibliothek von Rocket Scream. Sie macht auch das Verwenden der in der Arduino bereitgestellten sleep-API (sleep.h) überflüssig.

Die Bibliothek gibt es hier unter GitHub[10] zum Download als ZIP-Datei. Nach dem Herunterladen fügen Sie über den Menü-Pfad Sketch > Include Library > Add .ZIP Library... die Bibliothek der Arduino IDE zu. In einem Sketch müssen Sie dann nur noch die Headerdatei LowPower.h inkludieren ...

... und die entsprechende Routine für den Tiefschlaf nutzen, die auch vom Typ des Mikrocontroller abhängt, wie Sie der Klassendefinition für LowPowerClass (siehe Headerdatei) entnehmen können. Beim Uno liegt ein ATMega328P vor, weshalb der nachfolgende Sketch folgenden Aufruf nutzt:

LowPower.idle(SLEEP_1S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, 
SPI_OFF, USART0_OFF, TWI_OFF);

Die MCU wird für einen Zeitraum bis zu 8 Sekunden (Parameter SLEEP_xS) schlafen gelegt. Für eine Sekunde gibt es zum Beispiel SLEEP_1S. Währenddessen deaktiviert die Bibliothek ADC, Timer 0 bis 2, SPI-Bus, I2C-Bus (TWI), und den USART0 (serieller Ausgang 0).

Als Beispiel fungiert das Auslesen eines TMP36-Temperatursensors an einem Arduino Uno. Alle 8 Sekunden liest ein Sketch den aktuellen Sensorwert. Über den Einsatz dieses Sensors hatte ich bereits in einem vergangenen Beitrag[11] geschrieben.

Gleichzeitig zeigen sowohl die eingebaute LED des Arduino-Boards als auch die am selben Pin liegende externe LED an, sobald die Messung erfolgt (LED an) und abgeschlossen ist (LED aus). Die LEDs dienen lediglich als zusätzliche Last.

Das Schaltungsdiagramm für das Experiment strukturiert sich wie der unteren Abbildung zu entnehmen ist. Der Sketch liest die Temperatur über den Analogport A0 aus, und steuert die LEDs am Digitalport 13 an, also sowohl die im Arduino-Board integrierte als auch die extra auf dem Breadboard hinzugefügte LED.

Schaltung mit TMP36-Temperatursensor und zusätzlicher LED als Last
Schaltung mit TMP36-Temperatursensor und zusätzlicher LED als Last
Sketch

Der Sketch zum Versuchsaufbau gestaltet sich sehr einfach und ist selbsterklärend. Interessant ist vor allem die Methode measure() mit den Aufrufen von LowPower.idle().

Die Ermittlung der Temperatur erfolgt ebenfalls in dieser Methode.

Durch Verstellen der boole'schen Variablen powerSave ist steuerbar, ob delay() oder der Tiefschlafmodus zum Einsatz kommt.

/******************************************************
*
* Auslesen eines TMP36 Temperatursensors
*
*
*****************************************************/

#include "LowPower.h" // Low-Power Bibliothek nutzen
bool powerSave = true; // Power-Save-Betrieb an oder aus

int tmp36Pin = 0; // TMP36 liegt am Analog-Port A0
int extraLED = 13; // Extra LED an Digitalport D13

void setup() {
// Alle Pins als Ausgänge setzen:
for (int pin = 0; pin < 20; pin++)
pinMode(pin, OUTPUT);
}

// Im Betrieb erfolgt eine kontinuierliche Messung:
void loop() {
measure();
}

void measure() {
// Extra LED an, weil Messung beginnt:
digitalWrite(extraLED, HIGH);

// Wert am analogen tmp36Pin auslesen
// und in Temperatur umrechnen:

int whatIRead = analogRead(tmp36Pin);
float voltage = whatIRead * 5.0 / 1024;
float celsius = (voltage - 0.5) * 100;

// Statt delay() echter 1 Sekunden Tiefschlaf

if(powerSave)
LowPower.idle(SLEEP_1S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF,
SPI_OFF, USART0_OFF, TWI_OFF);

else
delay(1000);

digitalWrite(extraLED, LOW); // Messung beendet

// Statt delay() echter 8 Sekunden Tiefschlaf
if(powerSave)
LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF,
SPI_OFF, USART0_OFF, TWI_OFF);

else
delay(8000);
}

Wem das zu aufwändig erscheint, kann auch einfach einen "leeren" Sketch (BareMinimum.ino) nutzen, und dort die Wirkung der Aufrufe von LowPower.idle() im Leerlauf untersuchen.

Arduino Pro Mini statt Arduino Nano

Wie bereits erwähnt, gibt es als Alternative zum Arduino Nano den Arduino Pro Mini, der rund ein Sechstel der Größe eines Arduino Uno aufweist, und über keinen USB-Adapter verfügt. Die Pro Minis gibt es in mehreren Varianten mit ATMega168P oder ATMega328P, sowie mit 3.3V bei 8MHz Taktfrequenz oder 5V bei 16MHz Taktfrequenz. Diese Arduino-Boards kamen ursprünglich von Sparkfun. Mittlerweile gibt es eine ganze Menge von geklonten chinesischen Pro Mini Boards zu Preisen von weit unter 2 Euro bei Alibaba.

Vorderseite eines Pro Mini. Über die Programm Header (rechts) lässt sich ein FTDI-Board anschließen
Vorderseite eines Pro Mini. Über die Programm Header (rechts) lässt sich ein FTDI-Board anschließen (Bild: sparkfun.com)

Billigboards machen oft keine Angabe darüber, um welche Variante es sich handelt, im Gegensatz zum nachfolgend abgebildeten Board von Sparkfun (3.3V, 8MHz).

Um die bei Ihnen vorliegende Variante festzustellen, legen Sie am Raw-Eingang eine Spannungsquelle mit 5V an, zum Beispiel ein auf 5V gejumpertes FTDI-Board (oder einen anderen UART-USB-to-TTL-Adapter). GND des UART-USB-to-TTL-Adapters verbinden Sie mit einem GND-Pin des Pro Mini. Nun lesen Sie mit einem Multimeter die am VCC-Ausgang des Pro Mini anliegende Spannung aus. Sind es 3.3V, handelt es sich um einen Pro Mini mit 3.3V und 8MHz. Sind es hingegen 5V, liegt ein Pro Mini mit 5V und 16MHz vor.

sparkfun.com
Die Rückseite des Pro Mini Boards. Zu beachten sind die ungewöhnlich positionierten Analogports A4, A5, A6, A7, von denen A4 und A5 als I2C-Bus dienen (Bild: sparkfun.com)

Hier noch ein hilfreicher Überblick über die Pinbelegung eines Arduino Pro Mini.

Die Pinbelegung des Pro Mini
Die Pinbelegung des Pro Mini

Am besten, Sie nehmen einen FTDI-USB-TTL-Adapter und schließen daran den Pro Mini an, um ihn zu programmieren. Für den Betrieb können Sie dann eine Batterieversorgung statt des Adapters verwenden.

bx4.com
Der Arduino Pro Mini lässt sich in Verbindung mit einem FTDI-Adapter gur programmieren (Bild: bx4.com)
Arduino-kompatible Low-Power Boards

Wer auf Nummer sicher gehen möchte, greift gleich zu Arduino-kompatiblen Boards, die Hersteller auf niedrigen Energieverbrauch getrimmt haben.

Der Moteino von LowPowerLab verbraucht beim üblichen Blink-Sketch rund 8 mA. Daneben gibt es auch den Moteino Mega mit ähnlichem Energieverbrauch. Im kleinsten Energieverbrauchsmodus sind es nur um die 6.5 µA.

LowPowerLap
Das energiesparende Moteino-Board kosten um die 10 Euro (Bild: LowPowerLap)

Der Mini Ultra 8 MHz von Rocket Scream verbraucht im extremen Low-Power-Modus nur rund 1.6 bis 1.7 µA. Die Pro-Variante bietet einen Anschluss für eine Lithium-Ionen-Batterie.

Mini Ultra 8 MHz Board von Rocket Scream
Mini Ultra 8 MHz Board von Rocket Scream (Bild: Rocket Scream)
Arduino Raw Iron

Alternativ könnten Maker auch auf die Idee kommen, ihr eigenes Arduino-Board zusammenzuschustern, also eine Bare-Bone-Lösung. Wie das geht, hatte bereits mein Beitrag über einen Selbstbau-Arduino[12] beschrieben. Einige der dort verwendeten Bauteile lassen sich dann gezielt durch weniger stromhungrige Varianten ersetzen oder ganz weglassen wie zum Beispiel die Onboard-LED.

ESP8266

Auch ESP8266-Boards wie NodeMCU und ESP32-Boards verfügen über die Möglichkeit des Tiefschlafs. Beispielsweise enthielt die Schaltung in der Folge über die Wetterstation mit dem Sensor BME680[13] einen ESP-01 für die Kommunikation über WiFi mit dem Dienst Thingspeak. Die ESP-MCUs verprassen reichlich Energie, auch wenn sie gerade nichts zu tun haben, weshalb der Maker die Controller schlafen legen sollte, sobald sie zur Untätigkeit verdammt sind. Dummerweise funktioniert beim ESP-01 das Schlafen legen weder über die Arduino-Core-Firmware noch über die dafür vorhandenen AT-Kommandos. Der Grund dafür ist, dass der externe RESET-Pin nicht mit dem XPD_DCDC-Pin (Deep Sleep Wake-up = GPIO16) verbunden ist.

Das Layout des ESP8266. Der XPD_DCDC-Pin befindet sich links unten im Bild
Das Layout des ESP8266. Der XPD_DCDC-Pin befindet sich links unten im Bild

Daher empfiehlt sich für diejenigen, die sich das Löten zutrauen, folgende Hardwaremodifikation (Hack). Man verbinde den RESET-Pin mit dem XPD_DCDC-Pin wie auf der folgenden Abbildung als blaue Linie illustriert.

In einem Hack verbindet der Maker REST-Pin des ESP-01 mit XPD_DCDC-Pin, um den Schlafmodus zu ermöglichen
In einem Hack verbindet der Maker REST-Pin des ESP-01 mit XPD_DCDC-Pin, um den Schlafmodus zu ermöglichen

Da ein ESP-01 nur Briefmarkengröße hat, muss das Löten sehr vorsichtig erfolgen. Dass der XPD_DCDC-Pin weit von der Antenne entfernt ist, erweist sich als Glück im Unglück.

Ist die Modifikation abgeschlossen, lässt sich der ESP-01 bei Firmwareprogrammierung oder im AT-Betriebsmodus zeitweise (bis etwa 71 Minuten) in den Tiefschlaf versetzen. Das entsprechende AT-Kommando lautet:

AT+GSLP=

Wer noch mehr sparen will, kann auch beim ESP-01 wagemutig die Power-LED eliminieren (rote LED, ganz oben rechts neben der Antenne).

Fazit

Im Gegensatz zu stationären Embedded Geräten mit Netzanschluss sind autonom arbeitende oder mobile Geräte auf eine unabhängige Energieversorgung angewiesen. Bei naiver Hardware-/Software-Konfiguration und -Programmierung kommt spätestens dann keine Freude mehr auf, sobald alle paar Tage oder sogar schon alle paar Stunden die Batterien ersetzt werden müssen. Das lässt sich nur durch geschickte Wahl der Hardwarekomponenten und durch programmatische Massnahmen vermeiden, wodurch sich der Verbrauch von 25mA im idealen Fall auf unter 5µA reduzieren lässt. Wem auch das noch zu hoch erscheint, nutzt Arduino-kompatible Varianten wie Moteino oder Mini Ultra {Pro}, die speziell auf Low-Power-Operation getrimmt sind.

Alle beschriebenen Maßnahmen bestehen wie bei jeder Art von Energiesparen darin, den Verbrauch spürbar zu senken, und zusätzlich regenerative Energiequellen wie die Sonne zu nutzen.

Es genügt aber nicht, nur den verwendeten Mikrocontroller zu betrachten. Auch komplexere Sensoren wie ein BME680 oder Zusatzhardware wie zum Beispiel Kommunikationshardware (ESP-01) besitzen Sleep-Funktionalität, da sie sonst im Standby-Betrieb signifikant Strom ziehen würden. Der verbrauchssensitive Maker sollte daher stets die Datenblätter all seiner Hardwarekomponenten zur Hand haben.

Stromverbrauch ist übrigens eines der Gebiete, in denen sich in der Regel normale Softwareentwicklung von der Entwicklung von Embedded Systemen unterscheidet. Entwickler von Smart Phones, Watches und Tablets können ein Lied davon singen.


URL dieses Artikels:
http://www.heise.de/-4002306

Links in diesem Artikel:
[1] https://www.amazon.de/RAGU-17B-Diodendurchlauftest-Hintergrundbeleuchtung-Messbereichserkennung/dp/B06W5G1VND/ref=sr_1_4?ie=UTF8&amp;qid=1521808476&amp;sr=8-4&amp;keywords=multimeter
[2] http://www.instructables.com/id/Digital-multimeter-shield-for-Arduino/
[3] http://wiki.happylab.at/w/Arduino_voltammeter
[4] https://www.heise.de/developer/artikel/Logic-Analyzer-3287114.html
[5] https://www.youtube.com/watch?v=W9X_DnGufO0
[6] http://www.home-automation-community.com/arduino-low-power-how-to-run-atmega328p-for-a-year-on-coin-cell-battery/
[7] http://www.instructables.com/id/SOLAR-POWERED-ARDUINO-WEATHER-STATION/
[8] http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf
[9] https://www.youtube.com/watch?v=urLSDi7SD8M
[10] https://github.com/rocketscream/Low-Power
[11] https://www.heise.de/developer/artikel/Lauschen-mit-Sensoren-3217195.html
[12] https://www.heise.de/developer/artikel/Do-it-Yourself-Projekt-iXduino-Arduino-on-a-Breadboard-3198567.html
[13] https://www.heise.de/developer/artikel/Ueberraschungsei-fuer-Wetterfroesche-dank-BME680-ESP8266-Arduino-ThingSpeak-3979158.html

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 26. März 2018 um 10:52

Gutes Echo mit ESP8266 oder ESP32

Von heise online

zurück zum Artikel

Intelligente Sprachassistenten à la Apple Homepod, Google Home oder Amazon Echo verkaufen sich zur Zeit wie warme Semmeln, und bilden das Zentrum so mancher Smart-Home-Lösung. Wie aber kann der Maker Geräte bauen, die sich dort relativ einfach integrieren lassen?

Warum Amazon Echo

In diesem Beitrag liegt der Fokus auf Amazon Echo. Diese Wahl soll keine negative Bewertung der Lösungen von Google oder Apple assoziieren. Die Entscheidung für Amazon fällt einzig aus dem Grund, weil deren Produkte mittlerweile am meisten verbreitet sind. Demzufolge haben sich auch schon einige Open-Source.Entwickler auf diesem Gebiet engagiert. Grund genug, ein Auge auf die Möglichkeiten zu werfen, die sich dem Maker bieten.

Do the Wemo Dance

Jetzt wäre es natürlich die naheliegendste Möglichkeit, sich als Amazon-Entwickler zu registrieren, um entsprechende Skills und Echo-kompatible Hardware bereitzustellen. Für viele sehr einfache Anwendungsfälle ist das aber gar nicht notwendig. Damit sind solche Beispiele gemeint, bei denen sich die Steuerung eines IoT-Geräts auf das Ein- und Ausschalten reduzieren lässt. Die Killerapplikation sind in diesem Zusammenhang Lampen oder Steckdosen, die sich von einem Microcontroller aus über Relais schalten lassen.

Findige Entwickler haben deshalb die Wemo-Lösung von Belkin unter die Lupe genommen. Wie jedes in Echo integrierbare Gerät, enthält eine Wemo-Steckdose Funktionalität, um sich über WLAN mit einem Echo, Echo Dot, Echo Spot, oder Echo View zu koppeln. Was liegt also näher als dieses Protokoll nachzubauen und in einer Bibliothek bereitzustellen. Damit können Maker ihre eigene Lösung als Belkin Wemo ausgeben.

Funktion von Amazon Echo

Wie funktioniert überhaupt das Zusammenspiel zwischen Echo-Produkt und Geräten wie zum Beispiel einer Belkin Wemo Steckdose?

Fordert der Benutzer ein Echo-System zum Auffinden neuer Geräte auf, schickt es per UDP-Broadcast eine Meldung an alle Geräte im vorliegenden WLAN. Kopplungswillige, neue Geräte antworten mit ihrer URL-Adresse, worauf Echo sie um ihre Service-Beschreibung bittet. Daraufhin schickt das jeweilige Gerät die Gerätebeschreibung (setup.xml) zurück. Diese Zuordnung (Gerät, Name, Charakteristik, ...) merkt sich Echo in einer Geräteliste. Fordert der Nutzer per Sprache oder App ein bekanntes Gerät zu einer von diesem Gerät unterstützten Aktion auf, bittet Echo das Gerät per TCP/Webservice-Aufruf um entsprechende Zustandsänderung (SetBinaryState), was das angesprochene Gerät bestätigt.

Eine schlichte Steckdose des Typs Belkin Wemo beispielsweise kennt nur zwei alternierende Zustände, an und aus. Demzufolge hören sie auf sehr einfache Kommandos.

ESP32 und ESP8266

Um eine einfache Integrationsmöglichkeit in das Amazon-Echo-Universum zu illustrieren, ist ein ESP8266 oder ein ESP32 Board notwendig. In meiner Serie gab es zu beiden MCUs schon Artikel (ESP8266 Teil 1[1] und Teil 2[2], ESP32[3]).

Empfehlenswert als Boards sind beispielsweise die NodeMCU-Varianten mit ESP32 oder ESP8266 (ESP-12e oder ESP 12-f). Prinzipiell sollte sich aber jedes Board eignen.

Arduino Core

Für unsere Zwecke ist die Arduino IDE notwendig. Damit sie mit ESP-Boards umgehen kann, existieren sogenannte Arduino Cores für ESP8266- beziehungsweise ESP32-Boards. Deren Installation in die IDE ist auf den Implementierungsseiten beschrieben.

  • ESP8266: siehe github[4]
  • ESP32: siehe github[5]

Die Boards mit ESP8266 oder ESP32 verwenden üblicherweise andere UART-Hardware, sodass die Installation zusätzlicher Treiber notwendig ist, typischerweise die UART-to-USB-Treiber von SiLabs für CP210x-Chips [6]oder die Treiber für CH34x-Chipsets[7].

Haben die Installationen von Arduino Core und USB-Driver geklappt, können Sie in der Arduino IDE unter dem Menü Tools den COM-Port und das jeweils verwendete Board spezifizieren, wobei es bei ESP8266-Boads meistens im Falle von NODEMCU das NODEMCU 1.0 (oder sonst Generic ESP8266 Module) tut, und bei ESP32-Boards ESP32 Dev Module. In meinem Fall lag ein Board des Typs Wemos Lolin vor.

Fauxmo statt Wemo

Wir nutzen den Arduino Core für ESP32 und ESP8266. Dadurch lassen sich die Boards im gewohnten Stil mit der Arduino IDE programmieren.

Allerdings sind zwei Bibliotheken notwendig, zum einen fauxmoESP, und zum anderen eine Bibliothek für asynchrone Kommunikation.

Die essenzielle Bibliothek für unser "trojanisches Pferd" firmiert unter dem Namen fauxmoESP[8]. Der Ursprung von fauxmoESP ist eine entsprechende Python-Bibliothek[9], die von Maker Musings stammt. Die C/C++- Umsetzung haben wir Bibi Blocksberg (der Name ist hoffentlich ein Pseudonym), Xose Pérez (ESP8266) und Frank Hellmann (ESP32) zu verdanken. Zudem benötigt fauxmoESP eine C++-Bibliothek zur asynchronen Kommunikation, entweder AsyncTCP[10] für ESP32-Boards oder ESPAsyncTCP[11] für ESP8266-Boards.

Beide Bibliotheken sollten Sie sich von Github holen und jeweils über das Menü Sketch > Include Library > Add .ZIP Library der IDE bekannt machen.

In der Amazon Alexa App tauchen nach dem Koppeln die LEDs Merkel und Schulz auf
In der Amazon Alexa App tauchen nach dem Koppeln die LEDs Merkel und Schulz auf

Falls Sie es interessieren sollte: Warum fauxmo funktioniert wie es funktioniert, erläutert der Ur-Vater von fauxmo in einem interessanten Artikel[12].

Kleine Warnung vorweg: Die Lösung scheint in Kombination mit ESP8266-Core und ES32-Core noch nicht für alle Generation beziehungsweise Typen von Echo-Hardware zu funktionieren - so soll es in Geräten der zweiten Generation unter Umständen zu Problemen kommen. Ich hatte beispielsweise damit zu kämpfen, dass Alexa beim Sprachbefehl "Alexa, suche neue Geräte!" meine Selbstbau-Fauxmos nicht finden konnte, diese sich aber hinterher trotzdem auf der Alexa App aufgelistet befanden, und über Sprache steuerbar waren. Generell scheint die Verwendung mit ESP8266 momentan weniger Zicken zu machen als mit einem ESP32-Board.

Nutzung der Bibliothek

Die Verwendung der Bibliothek in eigenen Programmen ist äußerst simpel.

  • Eine Variable des Typs fauxmoESP definieren.
  • Über diese Variable im Setup alle gewünschten Geräte anmelden, und fauxmo einschalten.
  • In den Callback-Routinen Aktionen ausführen. Letzteres wird weiter unten eine Demoanwendung veranschaulichen.

Damit lautet das prinzipielle Gerüst eines fauxmo-basierten Sketches:

#include // Headerdatei inkludieren

fauxmoESP fauxmo; // Zugriff auf fauxmo

voidsetup() {

Serial.begin(115200);

... Mit WLAN verbinden...

fauxmo.addDevice("Gerät Eins"); // Zwei Geraete anmelden
fauxmo.addDevice("Gerät Zwei");

fauxmo.enable(true); // Jetzt fauxmo aktiv schalten

fauxmo.onSetState([](unsignedchar device_id, constchar* device_name, bool state) {
Serial.printf("[MAIN] Device #%d (%s) state: %s\n", device_id, device_name, state ? "ON" : "OFF");
});
fauxmo.onGetState([](unsignedchar device_id, constchar* device_name) {
return true; // Status zurückmelden
});

}

voidloop() {
fauxmo.handle(); // Eigentliche Event-Loop
}

Portzuordnung

In der Arduino IDE haben die verschiedenen Ports einfache Zuordnungen, etwa D1 = 1 oder D2 = 2, was der Tatsache geschuldet ist, dass die IDE sich ursprünglich stark an Arduino-Boards angelehnt hat. Für ESP2866- oder ESP32-Boards mit Arduino Core verhält sich die Angelegenheit ein wenig schwieriger, da sie ein anderes Layout ihrer Ausgänge besitzen. Die BUILTIN_LED lautet bei einem NODEMCU 1.0 16 (= D0). Hier gibt es folgende Portzuordnungen:

ESP8266  Arduino IDE
D0       16
D1 5
D2 4
D3 0
D4 2
D5 14
D6 12
D7 13
D8 15
D9 3
D10 1
Schaltungsbeispiel

Als Beispielsanwendung sollen zwei schlichte LEDs zum Einsatz kommen. Beide meldet der Sketch als Wemo-Geräte bei Amazon Echo an, sodas sie sich mittels Alexa ein- und ausschalten lassen. Das Beispiel nutzt einen Baustein des Typs NodeMCU (Wemos Lolin) auf Basis des ESP8266. Stattdessen kann auch ein ESP32-Board zum Einsatz kommen, aber für das simple Beispiel ist bereits der ESP8266 unterfordert.

Die Schaltung verwendet lediglich die Ports D0, D1 des Boards zur Ansteuerung der LEDs
Die Schaltung verwendet lediglich die Ports D0, D1 des Boards zur Ansteuerung der LEDs

In der Schaltung sind zwei LEDs (rot und blau) jeweils über 220Ω Widerstände an die Ports D0 (= Pin 16 des Wemos Lolin v3 / NodeMCU Boards) und D1 (= Pin 5 des Wemos Lolin v3 / NodeMCU Boards) angeschlossen. GND des Boards wird mit den beiden LEDs gemeinsam über das Breadboard geerdet (blaue Verbindung).

In einem anwendungsnäheren Szenario würden die Ausgänge keine LEDs ansteuern sondern Relais, über die sich größere Lampen in einem 12V-Stromkreis ein- oder ausschalten lassen.

Fauxmo Sketch

Der zugehörige Sketch folgt ganz dem Muster, das wir oben kennengelernt haben. Das Programm gaukelt dem Echo-System zwei Wemo-Geräte namens "Merkel" und "Schulz" vor. Wir hätten bis zu gut einem Dutzend Geräte einführen können.

Hinweis: Bei den meisten Boards mit ESP8266 oder ESP32 existiert eine Flash- beziehungsweise Boot-Taste neben einer Reset-Taste. Um das Board mit einem neuen Sketch bespielen zu können, muss beim Reset die Flash-Taste gedrückt sein. Das liegt daran, dass ein Sketch zusammen mit dem Arduino Core in Wirklichkeit eine Firmware bildet. Zwar führt die IDE beziehungsweise die Werkzeuge für ESP8266/ESP32-Programmierung eines Reset aus, aber es empfiehlt sich, die Reset-Taste selbst manuell bei gedrückter Flash-Taste zu betätigen. Dann klappt es mit dem Aufspielen des Sketches. Ohne Betätigen der Flash-Taste geht das Board einfach in den Ausführungsmodus und verweigert sich jedem Upload.

//***********************************************************
//
// Demoanwendung um mittels eines ESP32- oder ESP8266-Boards
// eine Belkin Wemo Steckdose zu simulieren
// Michael Stal, 2018
// Creative Commons
//
//************************************************************

#include

#ifdef ESP32 // Im Falle eines ESP32-Boards
#include
#else // bei einem ESP8266-Board
#include
#endif

// Die wichtigste Bibliothek ist fauxmoESP
#include "fauxmoESP.h"

// Zwei Lampen
#define MERKEL_LED 5
#define SCHULZ_LED 16

// Volle Kanne am seriellen Port
#define SERIAL_SPEED 115200

#define WL_SSID "StalWLAN"
#define WL_PASS "4242424242"

#define LAMPE1 "Merkel"
#define LAMPE2 "Schulz"

fauxmoESP fauxmo; // Objekt zum Zugriff auf fauxmo

//***********************************************************
//
// wifiSetup dient zur Verbindung ins WLAN >>WL_SSID<<
//
//************************************************************

void wifiSetup() {
// Das ESP-Board wird zur Station gemacht:
WiFi.mode(WIFI_STA);

// Verbindungsaufbau
Serial.printf("[WIFI] Verbinden zu %s ", WL_SSID);
WiFi.begin(WL_SSID, WL_PASS);

// Warten bis Verbindungsaufbau erfolgt ist
while (WiFi.status() != WL_CONNECTED) {
Serial.print(">");
delay(100);
}
Serial.println();

// Verbunden!
Serial.printf("[WIFI] Client Modus, SSID: %s, IP Adresse: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str());
}

//***********************************************************
//
// setup initiiert den WLAN setup,
// schaltet beide Lampen aus,
// aktiviert fauxmo,
// meldet beide Lampen an,
// und definiert dafür Callbackhandler
//
//************************************************************

void setup() {
// Seriellen Port initialisieren
Serial.begin(SERIAL_SPEED);
Serial.println();
Serial.flush();

// Hier erfolgt der Verbindungsaufbau zum WLAN
wifiSetup();

// Die beiden LEDs
pinMode(MERKEL_LED, OUTPUT);
digitalWrite(MERKEL_LED, LOW);

pinMode(SCHULZ_LED, OUTPUT);
digitalWrite(SCHULZ_LED, LOW);


// Die Bibliothek lässt sich aktivieren und deaktivieren.
// Im deaktivierten Modus lassen sich Geraete weder finden noch schalten

fauxmo.enable(true);

// Alexa virtuelle Geraete unterjubeln
fauxmo.addDevice(LAMPE1);
fauxmo.addDevice(LAMPE2);

// Callback, sobald Lampe von Alexa geschaltet wird:
fauxmo.onSetState([](unsigned char device_id, const char * device_name, bool state) {
Serial.printf("[MAIN] Device #%d (%s) Zustand: %s\n", device_id, device_name, state ? "AN" : "AUS");
if ( (strcmp(device_name, LAMPE1) == 0) ) {
Serial.println("Merkel wird geschaltet");

if (state) { // Abhaengig vom Zustand Lampe ein-/ausschalten
digitalWrite(MERKEL_LED, HIGH);
} else {
digitalWrite(MERKEL_LED, LOW);
}
}
if ( (strcmp(device_name, LAMPE2) == 0) ) {
Serial.println("Schulz wird geschaltet");
if (state) { // Abhaengig vom Zustand Lampe ein-/ausschalten
digitalWrite(SCHULZ_LED, HIGH);
} else {
digitalWrite(SCHULZ_LED, LOW);
}
}
});
}

//***********************************************************
//
// loop ist die Ereignisschleife unseres Fake Wemo
//
//************************************************************

void loop() {
// Asynchron auf Echo-Kontaktaufnahmen warten, und darauf reagieren
fauxmo.handle();
}

Nach dem Koppeln über Sprachbefehl "Alexa, suche neue Geräte" oder über die Alexa App (Android, iOS), finden sich die neuen Lampen als Wemo-Steckdosen in der Geräteliste, und lassen sich entweder von der App oder mit Sprachbefehlen steuern, etwa mit "Alexa, schalte Merkel an!". So einfach kann das Leben sein.

In der Amazon Alexa App tauchen nach dem Koppeln die LEDs Merkel und Schulz auf
In der Amazon Alexa App tauchen nach dem Koppeln die LEDs Merkel und Schulz auf
Fazit

In der vorliegenden Folge haben wir kennengelernt, wie sich an einem ESP32- oder ESP8266-Board angeschlossene Geräte über Amazon Echo ansteuern lassen. Das funktioniert allerdings nur, sofern diese Geräte wie eine Lampe oder Steckdose nur zwei Zustände kennen, nämlich ein und aus. Der Trick besteht darin, dass die Bibliothek fauxmoESP dem Echo-Gerät vorspielt, es verkörpere eine Belkin Wemo Steckdose. Wer einen Raspberry Pi, eine Synology-Workstation oder einen Linux/Mac-Computer nutzt, kann dort die Python-Version von fauxmo zum gleichen Zweck nutzen. Siehe die erweiterte Version von n8henrie[13] oder die ursprüngliche Version von makermusings[14].

Für komplexere Interaktionen und Geräte müssen Maker wohl oder übel auf der Amazon-Plattform (Amazon Lambda) Hand anlegen und komplexere Skills implementieren.


URL dieses Artikels:
http://www.heise.de/-3991889

Links in diesem Artikel:
[1] https://www.heise.de/developer/artikel/Arduino-goes-ESP8266-3240085.html
[2] https://www.heise.de/developer/artikel/Make-your-own-ESP8266-WiFi-Shield-3246107.html
[3] https://www.heise.de/developer/artikel/ESP32-Neuer-IoT-Chip-von-Espressif-3506140.html
[4] https://github.com/esp8266/Arduino
[5] https://github.com/espressif/arduino-esp32
[6] https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers
[7] http://www.wch.cn/download/CH341SER_ZIP.html
[8] https://bitbucket.org/xoseperez/fauxmoesp
[9] https://github.com/makermusings/fauxmo
[10] https://codeload.github.com/me-no-dev/AsyncTCP/zip/master
[11] https://codeload.github.com/me-no-dev/ESPAsyncTCP/zip/master
[12] http://www.makermusings.com/2015/07/13/amazon-echo-and-home-automation/
[13] https://github.com/n8henrie/fauxmo
[14] https://github.com/makermusings/fauxmo

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 14. März 2018 um 07:00

FreshRSS 1.10.2

Von Alkarex

This version is only relevant for Docker.

Changelog:

  • Bug fixing
    • Fix Docker image for OPML import #1819
    • Fix Docker image for CSS selectors #1821
    • Fix Docker other missing PHP extensions #1822
  • 09. März 2018 um 11:08

Überraschungsei für Wetterfrösche dank BME680, ESP8266, Arduino & ThingSpeak

Von heise online

zurück zum Artikel

In der heutigen Folge soll eine von einem Arduino-Board betriebene Wetterstation periodisch Umweltdaten erfassen, und diese Daten mittels WiFi über HTTP in eine Cloud-Plattform übertragen. Interessierte Zeitgenossen können dann live am mobilen oder stationären Gerät die Entwicklung der Messdaten in der Cloud verfolgen. Um dieses Ziele zu erreichen, müssen wir uns mehreren Herausforderungen stellen. Welche das sind und wie sie sich lösen lassen, zeigt der vorliegende Artikel. Seien Sie aber unbesorgt - es gibt ein Happy End!

Alles in der Cloud

Wenn wir Sensor-Daten der Wetterstation in der Cloud speichern wollen, können wir PasS/IaaS-Plattformen wie Amazon AWS oder Microsoft Azure nutzen. Einfacher und preisgünstiger gestaltet sich die Aufgabe mit einer speziell für Datenanalytik konzipierten Lösung. ThingSpeak ist eine solche IoT-Plattform und ermöglicht das Ablegen von Sensordaten. Sie integriert darüber hinaus MATLAB-Werkzeuge von MathWorks für komplexere Datenvisualisierungen. Ein freier Account stellt eine kostenlose Möglichkeit dar, um Daten-Kanäle einzurichten, die der Nutzer allerdings höchstens alle 16 Sekunden aktualisieren darf. Kanäle können dabei privat oder öffentlich zugänglich sein. Der Charme von ThingSpeak liegt in seiner einfachen Nutzbarkeit dank schlichtem HTTP, das es für das Lesen oder Schreiben von Daten verwendet. Die Kanäle lassen sich über Webbrowser oder Apps beobachten.

Zum Registrieren eines neuen Kontos gehen Interessierte auf die ThingSpeak-Webseite[1].

Anmeldung als neuer Nutzer auf der ThingSpeak
Anmeldung als neuer Nutzer auf der ThingSpeak

Nach der erfolgreichen Erstellung eines neuen Kontos kann die neue Nutzerin sich in das eigene anmelden.

Erstellen eines neuen Benutzerkontos auf ThingSpeak
(Bild: Erstellen eines neuen Benutzerkontos auf ThingSpeak)

Ist das Konto fertig eingerichtet, kann der Nutzer durch einfachen Knopfdruck einen neuen Kanal erstellen: siehe hier[2]. Der Kanal braucht zumindest einen Namen, und zwischen eins und acht Daten-Feldern. Nur wer will, kann zusätzlich weitere Information wie geographische Position, eine externe Webseite oder Metadaten angeben.

Teilnehmer können ihre eigenen Kanäle anmelden
Teilnehmer können ihre eigenen Kanäle anmelden

Der neue Kanal taucht jetzt in der Hauptseite des Nutzers auf. Über die Registerkarte API Keys lassen sich die vertraulichen Zugriffsschlüssel zum Lesen und Schreiben abrufen.

Auf der Registerkarte erfährt der IoT-Maker seine API-Schlüssel, die er später in seinen Programmen benötigt
Auf der Registerkarte erfährt der IoT-Maker seine API-Schlüssel, die er später in seinen Programmen benötigt

In der Registerkarte Sharing ist das eingeschränkte Freigabe des Kanals für bestimmte Personen oder sogar die öffentliche Freigabe des Kanals möglich. In letzterem Fall kann jeder Nutzer weltweit den Kanal beobachten, etwa durch Eingabe der öffentlichen Channel ID. Der von mir für dieses Postings benutzte Kanal besitzt übrigens die Kennung 438188 und lässt sich über die Seite[3] lesen. Das ist auch programmatisch möglich, wie der Artikel noch später illustriert. Die ersten fünf Diagramme zeigen den zeitlichen Verlauf der Sensordaten-Felder, das sechste eine MATLAB-Analyse über die Häufigkeiten bestimmter Temperaturwerte.

ThingSpeak erlaubt die Erstellung privater Kanäle.

Einen privaten Datenkanal kann nur dessen Ersteller nutzen
Einen privaten Datenkanal kann nur dessen Ersteller nutzen

Alternativ ist auch die Kreierung eines öffentlich zugänglichen Kanals möglich. Öffentliche Kanäle haben eine eindeutige Kennung. Sie lassen sich über Web-Browser beobachten, oder auch von mobilen Geräten aus. Etwa von einem Tablet

Kanalbeobachtung für die Wetterstation auf einem iPad
Kanalbeobachtung für die Wetterstation auf einem iPad

Oder auch über Apps:

Eine der Apps zum Beobachten von öffentlichen ThingSpeak-Kanälen
Eine der Apps zum Beobachten von öffentlichen ThingSpeak-Kanälen
Umweltsensor BME680

Die Datenablage wäre also jetzt geklärt. Nur woher kriegen wir eigentlich unsere physikalischen Messwerte?
Der Sensor BME680 von Bosch Sensortec[4] misst Umweltgrößen und adressiert speziell kleinere und mobile Geräte. Er erweitert den bekannten Sensor BME280 aus gleichem Hause. Zu seinen Messgrößen gehören Temperatur (-45...85°) , Luftfeuchtigkeit (0...100%), Luftdruck (300...1100hPa), Höhe, und Luftqualität im Raum (Indoor Air Quality). Dabei liegt sein Stromverbrauch bei wenigen Micro-Ampere. Mit Ausmaßen von 3.0mm x 3.0mm x 0.93mm zeigt sich der Sensor gut gewappnet, um eine kleinere Wetterstation oder ein Wearable zu betreiben. Die Luftbelastung ermittelt der BME680 in Form eines Widerstandswerts in der Einheit KOhm. Je niedriger dieser Widerstand ausfällt, desto mehr Teilchen sind in der Luft. Bosch berechnet daraus den Indoor Air Quality Index. Das funktioniert aber nur mit einer speziellen Bibliothek des Herstellers (https://github.com/BoschSensortec/BME680_driver), da dazu auch einige Betriebswerte des Sensors ins Spiel kommen. Wollen Sie den Index berechnen, müssen Sie folglich diese Bibliothek in Ihren Sketch integrieren. Weitere Details über den Sensor können sie dessen Datasheet [5]entnehmen.

Der Sensor BME680 misst verschiedene Umweltgrößen
Der Sensor BME680 misst verschiedene Umweltgrößen (Bild: Bosch Sensortec)

Natürlich erwerben Maker den Sensor üblicherweise nicht “nackt”, sondern in Form eines Breakout-Boards. Die Produkte stammen von Herstellern wie BlueDot, Adafruit, Watterott, MikroElektronika, Octopus oder Pimeroni. Die meisten Breakout-Boards stellen eine I2C- und als Alternative eine SPI-Schnittstelle zur Verfügung, und haben einen Logic Level Konverter onboard, sodass der Nutzer den Sensor mit Spannungen von 3V-5V betreiben kann.

Für den vorliegenden Beitrag findet ein entsprechendes Board von Watterott[6] zu preisgünstigen 15,95 Euronen Verwendung (siehe Abbildung).

Watterott
BME680-Breakout-Board von Watterott (Bild: Watterott)

Beim Anschluss habe ich mich für I2C (auch bezeichnet mit IIC, I2C, TWI) entschieden, um mit zwei Leitungen für die Kommunikation zwischen Arduino und BME680 auszukommen. Nähere Details zu I2C hat dieser Blog bereits früher vorgestellt[7].
Unter I2C/TWI besitzt der Sensor entweder die eindeutige I2C-Kennung 0x76 oder 0x77, je nachdem ob der Pin SDO auf 0 liegt oder auf 1. Letzteres sofern gleichzeitig Pin CS auf 1 liegt. Jedenfalls verbinden Maker IIC-Takt und Datenleitungspins von Arduino und Breakout-Board abhängig vom gewählten Arduino-Board.

Auf der Arduino IDE ist für die Ansteuerung des BME680 eine Bibliothek von Adafruit verfügbar. Da die BME680-Boards direkten Zugriff auf den Sensor implementieren, ist die Adafruit-Bibliothek wie auch zum Beispiel die Bibliothek von BlueDot für das Watterott-Breakout-Board ebenfalls nutzbar. Suchen Sie also im Bibliotheksmanagement der Arduino IDE nach dem Begriff BME680 und installieren Sie die entsprechende Bibliothek von Adafruit. Zwecks manueller Installation lässt sich die Bibliothek auch über GitHub beziehen: hier geht es zur Bibliothek[8].

Die Programmierung ist selbsterklärend. bme.setup() startet den Sensor, bme.performReading() führt die Messung durch. Danach lassen sich über die Variable bme die Messwerte auslesen. Die Initialisierung am Anfang von setup() habe ich der Dokumentation von Bosch Sensortec entnommen.

// Adafruit-Bibliothek für BME680
#include
#include
#include "Adafruit_BME680.h"

// Luftdruck auf Meereshoehe:
#define SEALEVELPRESSURE_HPA 1013.25

Adafruit_BME680 bme; // Zugriff ueber I2C

double humidity = 0.0; // Feuchtigkeit
double temperature = 0.0; // Temperatur
double pressure = 0.0; // Druck
double gas = 0.0; // Gas/Luftqualitaet
double est_altitude= 0.0; // Ungefaehre Hoehe

void setup()
{
Serial.begin(9600); // seriellen Monitor starten

if (!bme.begin()) {
Serial.println("Keinen BME680 Sensor gefunden!");
while (1);
}

// Initialisierung von Oversampling und Filter
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}

void loop()
{
measurement(); // Messwerte erfassen
}

void measurement(void)
{
// Erst den bme680 auslesen
if (! bme.performReading()) {
Serial.println("Fehler beim Messen ");
return;
}

// Werte ermitteln:
temperature = bme.temperature;
pressure = bme.pressure / 100.0;
humidity = bme.humidity;
gas = bme.gas_resistance / 1000.0;
est_altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);

// und am seriellen Monitor ausgeben
Serial.print("Temperatur = ");
Serial.print(temperature);
Serial.println(" *C");

Serial.print("Luftdruck = ");
Serial.print(pressure);
Serial.println(" hPa");

Serial.print("Feuchtigkeit = ");
Serial.print(humidity);
Serial.println(" %");

Serial.print("Gas = ");
Serial.print(gas);
Serial.println(" KOhms");

Serial.print("Ungefaehre Hoehe = ");
Serial.print(est_altitude);
Serial.println(" m");

Serial.println();
delay(2000);
}

Die Ausgabe schaut bei einem Testlauf meiner Schaltung wie folgt aus:

Temperatur = 24.13 *C
Luftdruck = 939.03 hPa
Feuchtigkeit = 31.02 %
Gas = 60.68 KOhms
Ungefaehre Hoehe = 636.94 m

Temperatur = 24.13 *C
Luftdruck = 939.05 hPa
Feuchtigkeit = 31.00 %
Gas = 61.08 KOhms
Ungefaehre Hoehe = 636.94 m

Bosch empfiehlt, den Sensor längere Zeit einzubrennen, damit er stabile Messwerte liefert. Speziell am Anfang ist sonst zum Beispiel der gemessene Luftwiderstand zu ungenau. Lassen Sie Ihre Schaltung daher ruhig initial für 24-48 Stunden laufen.

Arduino Nano

Für die Messwerterfassung und die Integration aller Komponenten kommt, wie nicht anders zu erwarten, ein Original-Arduino zum Einsatz.

Reichelt
Ein Arduino Nano ist kompakt und preisgünstig, aber trotzdem elistungsfähig (Bild: Reichelt)


Als Board verwendet der Beitrag den Arduino Nano mit 5V-Logik, der unter seiner Motorhaube einen ATmega328 beherbergt. Mit 2 KB SRAM und 32 KB Flashspeicher sowie 16 Mhz Frequenz ist das kompakte Board ideal für eine kleine Wetterstation geeignet. Pin Layout auf der Seite[9] verfügbar.

Das Pin-Layout eines Arduino Nano. Rechts im Bild sind die I2C-Pins A4 und A5 zu sehen
Das Pin-Layout eines Arduino Nano. Rechts im Bild sind die I2C-Pins A4 und A5 zu sehen

Für die Kommunikation über I2C mit dem BME680-Breakout-Board dienen beim Nano die Pins A4 und A5 (Daten über SDA, Takt über SCL).
Selbstverständlich können Sie statt des Nano auch ein anderes Arduino-Board einsetzen, das I2C oder SPI implementiert, etwa einen Leonardo, Uno oder Mega. Dann müssen Sie statt A4 und A5 die jeweils dort zuständigen Pins für I2C verwenden.

Kommunikation über ESP8266

Wir haben inzwischen die Cloudplattform, den Sensor und als zentrale Steuerung einen Arduino Nano. Das letzte Puzzlestück besteht aus der Kommunikation des Arduino-Boards mit der Cloud. Wer kein Arduino-Board mit integriertem (W)LAN-Anschluss sein eigen nennt (Arduino MKR1000, Yun, Arduino plus Ethernet-Shield oder WiFi-Shield …), muss sich anderweitig behelfen. Den dafür prädestinierten Chip von Espressif namens ESP8266 hatte dieser Blog schon ausführlich adressiert: siehe hier[10]. Ihn gibt es in verschiedenen Varianten für eine Handvoll Euro. Allgemein steht ESP8266 für einen Microcontroller mit zusätzlicher WiFi-Komponente. Soll ein Arduino Board günstig ins Internet, bietet sich daher der ESP8266 geradezu an. Größere ESP8266-Varianten wie nodemcu (ESP-12e oder ESP-12f) kann der Entwickler auch standalone einsetzen, also ganz ohne Arduino.

Für die Kommunikation der Wetterstation kommt ein ESP-01 aus der Produktfamile ESP8266 zum Einsatz
Für die Kommunikation der Wetterstation kommt ein ESP-01 aus der Produktfamile ESP8266 zum Einsatz

Wir nutzen trotzdem die einfachste Bauform, den ESP-01, um unsere Arduino-basierte Schaltung für lau mit WiFi-Kommunikation auszustatten.

Die Pinbelegung eines ESP-01 (ESP8266)
Die Pinbelegung eines ESP-01 (ESP8266)

Da der ESP-01 nur 3,3V verträgt, braucht die Wetterstation allerdings einen Logik Level Konverter zwischen den 3,3V des ESP-01 und der 5V Logik des Arduino Nano. Für unseren Zweck sollte der Konverter-Baustein neben den Stromanschlüssen Vcc und GND auf jeder Seite über 4 Kanäle verfügen. Beispielsweise tut es folgendes Produkt von SparkFun: Logic-Level-Konverter[11].

Ein Logic Level Converter vermittelt zwischen 3,3V und 5V Bausteinen
Ein Logic Level Converter vermittelt zwischen 3,3V und 5V Bausteinen (Bild: SparkFun)


Seinen “Saft” kann der ESP-01 von verschiedenen Seiten erhalten. In der vorliegenden Schaltung habe ich mich für ein FTDI-TTL-to-USB-Modul entschieden, da sich der ESP-01 damit auch direkt am Computer, beispielsweise über die Arduino IDE betreiben lässt.

Exemplarisch ein FTDI-Board von SparkFun. Damit können Entwickler den ESP-01 mit einem PC verbinden
Exemplarisch ein FTDI-Board von SparkFun. Damit können Entwickler den ESP-01 mit einem PC verbinden (Bild: SparkFun)

Das ist beispielsweise nötig, um ihn zu konfigurieren oder mit neuer Firmware zu flashen.
Es ergibt sich somit folgende Schaltung:

Um den ESP-01 standalone zu programmieren,  erfolgt eine Verbindung mit dem Computer über ein FTDI-USB-to-TTL Board
Um den ESP-01 standalone zu programmieren, erfolgt eine Verbindung mit dem Computer über ein FTDI-USB-to-TTL Board

Der ESP-01 hat standardmäßig einen AT-Kommandointerpreter als Firmware an Bord, und ist auf hohe Baudraten eingestellt. Da viele Arduino-Boards leider nur einen einzigen UART-Eingang besitzen, den sie per USB zum Laden von Firmware, Bootloadern und Sketches nutzen, müssen wir jeden weiteren seriellen Kanal per Software simulieren. Dazu gibt es die Bibliothek SoftwareSerial, dank der sich zwei beliebige Pins des Arduino als RX (Eingang) und TX (Ausgang) nutzen lassen, was aber nur bei niedrigeren Baudraten funktioniert. Daher besteht die erste Aufgabe darin, den ESP-01 entsprechend zu konfigurieren. Beispielsweise benötigen wir eine Rekonfiguration des ESP-01 auf eine Baudrate von 9600.
Zu diesem Zweck schließen wir den ESP-01 über einen FTDI-USB-to-TTL-Adapter direkt an den Desktop oder Notebook an, und rufen die Arduino IDE auf. Unter dem Menü Tools stellen wir den richtigen COM-Port des FTDI-Adapters ein. Wir wechseln in den seriellen Monitor (ebenfalls im Tools-Menü). Als Baudrate funktioniert zunächst dank Werkseinstellung meistens 112500 oder 57600 Baud (rechts unten im Fenster). Als Modus sollte Both NL and CR selektiert sein (links neben der Baudrate).

Die Verwendung der Arduino IDE ist nicht alternativlos. Anstelle der IDE erlauben Terminal-Werkzeuge wie putty, ssh einen Dialog mit dem ESP-01.

Sitzung mit dem AT-Kommandointerpreter des ESP-01. Für die Wetterstation sind Baudrate und ZUgang/Verbindung mit einem WLAN einzurichten
Sitzung mit dem AT-Kommandointerpreter des ESP-01. Für die Wetterstation sind Baudrate und ZUgang/Verbindung mit einem WLAN einzurichten

Um die Funktionstüchtigkeit des ESP-01 zu prüfen, gibt der Nutzer im Textfeld AT, gefolgt von der Eingabetaste ein, worauf die Rückmeldung Ok erscheinen müsste. Der Befehl AT+UART_DEF=9600,8,1,0,0 konfiguriert die Baudrate dauerhaft auf 9600 Baud.
Mit AT+CWMODE=1 lässt sich der ESP-01 als WLAN-Client einstellen.
Der AT-Befehl für die Verbindung zu einem existierenden WLAN lautet: AT+CWJAP=“SSID”,”PASSWORD”
Anschließend müsste der ESP-01 die erfolgreiche Verbindung zum WLAN bestätigen. Es sollte sich hierbei um das WLAN handeln, in die sich die Wetterstation später einloggt. Alternativ können Sie diese Verbindung aber auch aus dem Arduino-Sketch heraus bewerkstelligen.
Mittels Eingabe von AT+CIFSR erfährt der Entwickler dann unter anderem die IP, die der Access Point dem ESP-01 zugewiesen hat. Nun kennen Sie die Adresse der Wetterstation im eigenen Netz.
Nach dieser Konfiguration ist der ESP-01 für den Zugriff über den Arduino Nano gerüstet. Ein Arduino-Sketch sendet AT-Befehle über einen SoftwareSerial-Anschluss an den ESP-01, und kann diesen durch Ansteuerung des RESET-Eingangs sogar neustarten.

Kleiner Zwischen-Ausflug in Sachen ESP8266

Arduino Core für ESP8266

Der ESP8266 lässt sich übrigens auch wie ein Arduino Board innerhalb der Arduino IDE nutzen.
Dazu geben Sie im Sub-Menü Voreinstellungen (beziehungsweise Preferences) zusätzliche die URL folgenden Boardsmanagers ein:

 http://arduino.esp8266.com/stable/package_esp8266com_index.json 

Steht dort schon ein Eintrag, geben Sie an dessen Ende ein Komma ein, gefolgt von der genannten URL.
Anschließend können Sie im Tools > Board Menü die esp8266-Plattform installieren. Danach ist noch im Tools-Menü die Auswahl des richtigen COM-Ports und im Boards-Menü das Selektieren des Generic ESP8266 Module notwendig. Jetzt lassen sich Arduino-Sketches auf dem ESP-Modul hochladen und ausführen. Achtung: Dadurch wird auch eine neue Firmware (Arduino Core) auf den ESP-01 übertragen. Die AT-Firmware, die wir für die Wetterstation benötigen, geht damit verloren, und Sie müssen diese Firmware demzufolge bei Bedarf neu auf den ESP-01 flashen.

Zwei Modi

An dieser Stelle ist noch der Hinweis wichtig, dass ein ESP8266 zwei Laufzeitmodi kennt. Das eine ist der Programmausführungsmodus, also der Normalbetrieb, bei dem der ESP-01 ein Programm ausführt. Das andere ist der Flash-Modus bzw. Bootloader-Modus, der dem Entwickler gestattet, eine neue Firmware aufzuspielen. Wie bereits erwähnt, ist das Hochladen eines neuen Sketches über die Arduino IDE auf ein ESP8266-Board gleichbedeutend mit einem Flashen. Kurz und prägnant: Kein Flashmodus => Kein Sketchupload.
In welchem Modus der ESP läuft, entscheidet sich beim Boot/RESET des Chips. Ist während des Resets der Pin GPIO0 mit LOW belegt, startet der ESP8266 im Flashmodus, ansonsten im Ausführungsmodus.

Flashen des ESP8266

Es führen mehrere Wege nach Rom. Zum einen erlaubt das ESP8266 Flasher Werkzeug unter Windows ein relativ bequemes interaktives Flashen.
Dieses Tool erhalten Sie kostenlos unter der URL[12].
Die AT-Firmware ist über eine Webseite[13] downloadbar.
Mit dem kommandozeilenorientierten Python-Werkzeug esptool.py auf GitHub (siehe hier[14]) ist das Firmware-Flashen auch unter Windows, MacOS oder Linux möglich.

Schaltung

Nun liegen alle Teile der Wetterstation unserer Stückliste vor:

  • Breadboard
  • ESP-01 (ESP8266)
  • Arduino Nano
  • FTDI USB-to-TTL Adapter
  • BME680 Sensor
  • Logic Level Converter (3,3V und 5V) mit 4 Datenkanälen
  • Mehrere Steckverbindungsdrähte (male-male und female-male)
  • Zwei USB-Kabel, eines für Arduino Nano und eines für das FTDI-Board

Der Aufbau der Schaltung kann beginnen. Insgesamt ergibt sich folgendes Bild:

Auf dem Bild ist die komplette Schaltung mit allen beteiligten Komponenten zu sehen
Auf dem Bild ist die komplette Schaltung mit allen beteiligten Komponenten zu sehen

Fehlt nur noch die Software. Beachten Sie auch die Variable esp01, hinter der sich die serielle Verbindung vom Arduino Nano zum ESP-01 verbirgt:

  • Pin D6 des Nano fungiert als virtueller RX-Kanal und ist mit dem TX-Pin des ESP-01 verbunden
  • Pin D7 des Nano fungiert als virtueller TX-Kanal und ist mit dem RX-Pin des ESP-01 verbunden
  • Pin D8 des Nano ist mit dem RESET-Eingang des ESP-01 verbunden
Mit Hilfe der Bibliothek SoftwareSerial erhalten wir:

SoftwareSerial esp01(6,7)

Über diese serielle Verbindung sendet der Arduino-Sketch AT-Befehle zum ESP-01 beziehungsweise erhält von dort Rückmeldungen.

Das komplette Programm für die Wetterstation

Der Sketch verbindet sich bei setup() mit ESP-01, seriellen Monitor und BME280-Sensor. In der Ereignisschleife loop() fragt der Arduino Nano nach mindestens 16 Sekunden die Messwerte des BME680 ab (measurement()) und versendet diese über den ESP-01 an ThingSpeak (sendMeasurement()). sendMeasurement() verbindet sich mit der HTTP-basierten ThingSpeak-API (connectToThingSpeak()) und liefert dann über HTTP GET einen Update der Messwerte ab (writeToThingSpeakChannel()).

resetESP01() dient - nomen est omen - zum programmatischen RESET des ESP-01.

In der Vereinbarung für CHANNEL_WRITE_KEY hinterlegen Sie ihren Schlüssel zum Updaten des Kanals (im Listing rot markiert).

/************************************************** 
*
* Mini-Wetterstation
* mit Sensor BME380
* Arduino Nano und
* ESP8266
* (c) Michael Stal, 2018
* Creative Commons License
*
**************************************************/


/****** Nur wenn nicht Hardware-Serial ******/

#include
#define ESP_RX 6 // Nutzung der Pins D6
#define ESP_TX 7 // ... und D7
// Anschluss des ESP01 ueber ESP_RX und ESP_TX

SoftwareSerial esp01(ESP_RX, ESP_TX);
/********************************************/

/******** Adafruit BME680 Bibliothek ********/</span>

// Adafruit-Bibliothek für BME680

#include
#include
#include "Adafruit_BME680.h"

// Luftdruck auf Meereshoehe:
#define SEALEVELPRESSURE_HPA 1013.25

Adafruit_BME680 bme; // Zugriff ueber I2C

double humidity = 0.0; // Feuchtigkeit
double temperature = 0.0; // Temperatur
double pressure = 0.0; // Luftdruck
double gas = 0.0; // Gas/Luftqualitaet
double est_altitude= 0.0; // Ungefaehre Hoehe

/********************* THINGSPEAK ********************/
#define CHANNEL_WRITE_KEY ""
#define THINGSPEAK_IP "184.106.153.149"
#define THINGSPEAK_PORT 80
/******************* ESP spezifisch ******************/
#define ESP_SPEED 9600 // ESP-01 auf 9600 Baud eingestellt!
#define ESP_RESET 8 //Arduino D8 pin <-> RESET pin ESP-01

#define ESP_AT_COMMAND_CIPSTART "AT+CIPSTART=\"TCP\",\""
#define ESP_AT_COMMAND_CIPSEND "AT+CIPSEND="
#define ESP_AT_COMMAND_CIPCLOSE "AT+CIPCLOSE"
/********************** Timing ************************/
// Alles was mit Zeitintervallen zu tun hat
long sampleTime = 16; // Mindestzeit zwischen Datenversand
// ist 16 Sekunden
long startInterval = 0; // Start des Intervals
long delta = 0; // Zeit seit Start des Intervals

/****************** Fehlerbedingung *******************/
boolean errorCondition;

/**************************************************
*
* setup()
* initialisiert BME680 Sensor
* resetted ESP-01
* und stellt Verbindung zu ESP-01 her
*
**************************************************/

void setup()
{
Serial.begin(9600); // seriellen Monitor starten

if (!bme.begin()) {
Serial.println("Keinen BME680 Sensor gefunden!");
while (1);
}

// Initialisierung von Oversampling und Filter
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320°C für 150 msec

pinMode(ESP_RESET,OUTPUT);

esp01.begin(ESP_SPEED); // Mit ESP01 reden
resetESP01(); // Resetten des ESP01
startInterval = millis(); // Aktuelle Zeit erfassen
}

/**************************************************
*
* loop()
* Misst alle 16 Sekunden (sampleTime) die
* Unweltwerte, und sendet diese an ThingSpeak
*
**************************************************/

void loop()
{
errorCondition=false; // erst mal optimistisch sein

delta = millis()-startInterval; // Zeit seit Start

if ((delta / 1000) > sampleTime) // Zeit seit Zugriff > Sampling Zeit?
{
measurement(); // Messwert erfassen
sendMeasurement(); // Daten schreiben

// jetzt wird startInterval mit aktueller Zeit besetzt
startInterval = millis();
}

if (errorCondition)
{
Serial.println("Fehler aufgetreten");
delay (2000); // warten und dann wieder weiter
}
}

/**************************************************
*
* measurement()
* Liest den BME680 aus und speichert die Werte
* in Variablen, gibt diese auch am seriellen
* Monitor aus
*
**************************************************/

void measurement(void)
{
// Erst den bme680 auslesen
if (! bme.performReading()) {
Serial.println("Fehler beim Messen ");
return;
}

// Werte ermitteln und merken:
temperature = bme.temperature;
pressure = bme.pressure / 100.0;
humidity = bme.humidity;
gas = bme.gas_resistance / 1000.0;
est_altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);

// und am seriellen Monitor ausgeben
Serial.print("Temperatur = ");
Serial.print(temperature);
Serial.println(" *C");

Serial.print("Luftdruck = ");
Serial.print(pressure);
Serial.println(" hPa");

Serial.print("Feuchtigkeit = ");
Serial.print(humidity);
Serial.println(" %");

Serial.print("Gas = ");
Serial.print(gas);
Serial.println(" KOhms");

Serial.print("Ungefaehre Hoehe = ");
Serial.print(est_altitude);
Serial.println(" m");

Serial.println();
delay(2000);
}

/**************************************************
*
* sendMeasurement()
* verbindet sich mit ThingSpeak-Kanal
* und sendet eine HTTP GET, um die gemessenen
* Werte im Kanal zu speichern
*
**************************************************/

void sendMeasurement(void)
{

connectToThingSpeak(); // Verbindungsaufbau

if (!errorCondition) { // nur wenn Verbindung geklappt hat
String update = "GET /update?api_key=";
update += CHANNEL_WRITE_KEY;
update +="&field1=";
update += String(temperature);
update +="&field2=";
update += String(humidity);
update +="&field3=";
update += String(gas);
update +="&field4=";
update += String(pressure);
update +="&field5=";
update += String(est_altitude);
update += "\r\n\r\n";

writeToThingSpeakChannel(update); // Messwerte schreiben
}
if (errorCondition)
Serial.println("Verbindung hat nicht geklappt");
}

/**************************************************
*
* resetESP01()
* startet den angeschlossenen ESP-01 neu
*
**************************************************/

void resetESP01(void)
{
Serial.println("Reset des ESP01");
digitalWrite(ESP_RESET, LOW);
delay(1000);
digitalWrite(ESP_RESET, HIGH);
delay(10000);
Serial.println("ESP01 RESET beendet");
}

/**************************************************
*
* connectToThingSpeak()
* verbindet sich mit ThingSpeak-Kanal
*
**************************************************/

void connectToThingSpeak(void)
{
esp01.flush(); // Buffer leeren

String espCommand = ESP_AT_COMMAND_CIPSTART;
espCommand += THINGSPEAK_IP; // IP
espCommand += "\","; // PORT
espCommand += THINGSPEAK_PORT;
Serial.print("Verbindungsaufbau mit thingspeak ueber ");
Serial.println(espCommand);
esp01.println(espCommand);

if(esp01.find("error")) // Fehler aufgetreten?
{
Serial.println("Verbindungsfehler");
errorCondition=true;
}
}

/**************************************************
*
* writeToThingSpeakChannel()
* sendet einen Update-Befehl an den Kanal
* Uebergabe der Parameter mit command
*
**************************************************/

void writeToThingSpeakChannel(String command)
{
int len = command.length();
String specifyLengthCommand = ESP_AT_COMMAND_CIPSEND;
specifyLengthCommand += String(len);
Serial.print("Paketlaenge: ");
Serial.println(len);
// Mitteilen der Paketlaenge an ESP-01:
esp01.println(specifyLengthCommand);

if(esp01.find('>')) // Nach Nutzlast suchen
{
Serial.print("Kommando = ");
Serial.println(command);
esp01.print(command); // Eigentliches Update der Messdaten anfordern

delay(1000); // Warten auf ESP

while (esp01.available()) // Daten liegen Zeile fuer Zeile an
{
String line = esp01.readStringUntil('\n'); // Zeile lesen
if (line.length() == 1) // es war eine Leerzeile
{ // Inhalt nach Leerzeile lesen
line = esp01.readStringUntil('\n');
// ... und ausgeben:
Serial.print("Antwort: ");
Serial.println(line);
}
}
}
else
{
esp01.println(ESP_AT_COMMAND_CIPCLOSE); // Verbindung schliessen
Serial.println("Sendefehler");
errorCondition=true;
}
} // this is the end, my friend

Fazit

Wir haben in dieser Folge aus Arduino, ESP-01, BME680, Logic-Level-Konverter in Kombination mit der Cloud-Plattform ThingSpeak eine Wetterstation als IoT-Lösung zusammengebaut. Natürlich ließe sich diese Wetterstation relativ problemlos um weitere Sensoren erweitern. Einige andere Arten von Sensoren für dieses Einsatzgebiet (Regensensoren, Helligkeit, UV-Strahlung, Radioaktivität, Gewittererkennung, Bodenfeuchtigkeit, Feinstaub-Belastung) haben wir in früheren Artikeln bereits kennengelernt. Schön wäre des Weiteren ein wasserfestes Gehäuse sowie Batterie- oder LiPo-Betrieb, damit wir die Station auch ausserhalb von Wohnung oder Haus betreiben können. Oder ein GSM/GPRS-Modul, um das System sogar in abgelegeneren Gefilden autonom zum Einsatz zu bringen. Mittels SD-Kartenschreiber könnten wir die Wetterdaten auch temporär lokal speichern, sollte eine Verbindung einmal nicht möglich sein. Nötig ist auch ein ansprechendes Gehäuse. Die Wunschliste wächst bei längerem Nachdenken. Oder aber wir sind bereits mit der einfachen Lösung wunschlos glücklich.

Viel Spaß beim Experimentieren.


URL dieses Artikels:
http://www.heise.de/-3979158

Links in diesem Artikel:
[1] https://thingspeak.com/users/sign_up
[2] https://thingspeak.com/channels/new
[3] https://thingspeak.com/channels/438188
[4] https://www.bosch-sensortec.com/bst/products/all_products/bme680
[5] https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME680-DS001-00.pdf
[6] http://www.watterott.com/de/BME680-Breakout
[7] https://www.heise.de/developer/artikel/Anschluss-von-LCD-Displays-ueber-den-IIC-Bus-3217991.html
[8] https://github.com/adafruit/Adafruit_BME680
[9] http://www.pighixxx.com/test/pinouts/boards/nano.pdf
[10] https://www.heise.de/developer/artikel/Arduino-goes-ESP8266-3240085.html
[11] https://www.sparkfun.com/products/12009
[12] https://www.espressif.com/sites/default/files/tools/flash_download_tools_v3.6.3_0.rar
[13] https://www.espressif.com/sites/default/files/ap/esp8266_at_bin_v1.6.1.zip
[14] https://github.com/espressif/esptool

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 05. März 2018 um 12:40

FreshRSS 1.10.1

Von Alkarex

Changelog:

  • Deployment
    • New Docker image, smaller (based on Alpine Linux) and newer (with PHP 7.1) #1813
  • CLI
    • New command ./cli/prepare.php to make the needed sub-directories of the ./data/ directory #1813
  • Bug fixing
    • Fix API bug for EasyRSS #1799
    • Fix login bug when using double authentication (HTTP + Web form) #1807
    • Fix database upgrade for FreshRSS versions older than 1.1.1 #1803
    • Fix cases of double port in FreshRSS public URL #1815
  • UI
    • Add tooltips on share configuration buttons #1805
  • Misc.
    • Move ./data/shares.php to ./app/shares.php to facilitate updates #1812
    • Show article author email when there is no author name #1801
    • Improve translation tools #1808
  • 04. März 2018 um 18:04

Wo bin ich?

Von heise online

zurück zum Artikel

Für die meisten mobilen Geräte ist das Ermitteln der geographischen Position eine grundlegende Funktion. GNSS-Dienste wie GPS, Galileo, GLONASS, Beidou erlauben es, den aktuellen Ort mittels Satelliten zu bestimmen. Hierbei steht GNSS für Global Navigation Satellite System. Entsprechende Empfänger befinden sich inzwischen standardmäßig in Fahrzeugen, Smartphones, Kameras, Tablets, Drohnen oder Industriesteuerungen. Wie aber lässt sich eigene Hardware um diese Funktionalität erweitern?

GPS Faktencheck

GPS (Global Positioning System, ursprünglich NAVSTAR GPS, gibt es inzwischen schon seit den Siebziger Jahren. Insgesamt 24 Satelliten mit mittlerem Orbit von 20.200 km über der Erdoberfläche umkreisen unseren Planeten zweimal täglich. Je mindestens vier Satelliten bewegen sich dabei auf einer von sechs Bahnebenen, die 55 Grad gegen die Äquatorlinie geneigt sind. Dadurch sollen GPS-Empfänger zu jedem Zeitpunkt wenigstens vier Satelliten empfangen können. Nur mit Hilfe von vier Satelliten ist eine exakte Messung mit einer Fehlerabweichung von unter 10 Metern möglich.

Alle Satelliten senden diverse Information auf verschiedenen Frequenzen. Sie enthalten Atom- beziehungsweise Cäsium-Uhren, um eine genaue Zeit zusätzlich zur eigenen Position verschicken zu können. Diese Zeit berücksichtigt keine Schaltsekunden und weicht daher inzwischen rund 18 Sekunden von der koordinierten Weltzeit UTC ab, weshalb GPS-Empfänger die eigene Zeit entsprechend berechnen müssen. Aus den erhaltenen Daten kann der GPS-Empfänger unter anderem seine eigene Position, Bewegungsrichtung, Höhe und Geschwindigkeit ermitteln. Wissenswert am Rande ist die Tatsache, dass die GPS-Komponente wegen der hohen Geschwindigkeit von Satelliten relativ zum GPS-Empfänger relativistische Effekte berücksichtigen muss, weil sonst die Abweichung erheblich wäre.

Bewegung der GPS-Satelliten um die Erde. Schwarze Punkte haben Kontakt zum blauen Bezugspunkt auf der Erdoberfläche. Quelle: Wikipedia
Die Abbildung zeigt Bewegung der GPS-Satelliten um die Erde. Schwarze Punkte haben Kontakt zum blauen Bezugspunkt auf der Erdoberfläche. (Bild: wikipedia.org)
GPS-Module

Bei der Suche nach dem Stichwort „GPS module“ im Internet ergeben sich zahlreiche Treffer. Für Elektronikprojekte mit Arduino oder Raspberry Pi bieten die Neo 6M (oder 7M) - Bausteine des Schweizer Herstellers u-blox ein gutes Preis-/Leistungsverhältnis. Fertige Boards mit integriertem Neo6M-GPS-Baustein und brauchbarter passiver Keramik-Antenne schlagen mit Preisen ab 10-15€ zu Buche, wobei sich in den unteren Preisregionen überwiegend Nachbauten aus chinesischer Produktion tummeln. Zwar führen die billigen Klone nur serielle RX/TX-Pins nach außen, während die teureren Modelle zum Beispiel auch über einen I2C-Anschluss verfügen. Das tut dem Spaß aber keinen Abbruch.

Der Standard NMEA 183

Kommerzielle GPS-Module unterstützen den Standard NMEA 183 der National Marine Electronics Association, und senden typischerweise mit 8 Bit Datenbreite (inklusive einem Stop-Bit) ASCII-basierte Nachrichten über eine 4800 Baud-Verbindung.

Die Nachrichten sind wie folgt strukturiert, wobei jede Zeile eine separate Nachricht enthält:

$GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76 $GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A $GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70 $GPGSV,3,2,11,02,39,223,19,13,28,070,17,26,23,252,,04,14,186,14*79 $GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76 $GPRMC,092750.000,A,5321.6802,N,00630.3372,W,0.02,31.66,280511,,,A*43 $GPGGA,092751.000,5321.6802,N,00630.3371,W,1,8,1.03,61.7,M,55.3,M,,*75 $GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A $GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70 $GPGSV,3,2,11,02,39,223,16,13,28,070,17,26,23,252,,04,14,186,15*77 $GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76 $GPRMC,092751.000,A,5321.6802,N,00630.3371,W,0.06,31.66,280511,,,A*45

So beinhaltet das $GPGGA in der ersten Nachrichtenzeile Fix-Information, ob genügend Satelliten zum Positionieren zur Verfügung stehen.

$GPRMC stehen für eine Positionsbestimmung mit dem empfohlenen Minimum an Information (required minimum).

$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A

wobei hier

  • RMCbedeutet Recommended Minimum Sentence C - die minimale Menge an Information, die ein GPS-Modul liefern muss
  • 123519 Verbindung zu ausreichender Zahl an Satelliten erfolgte um 12:35:19 UTC
  • A Status (A= Active, V= Void)
  • 4807.038,N geographische Breite 48° 07.038' North
  • 01131.000,E die geographische Länge 11° 31.000' East
  • 022.4 Geschwindigkeit über Boden (in Knoten)
  • 084.4 Positionierungswinkel in Grad
  • 230394 das Datum - 23. März 1994
  • 003.1,W Magnetische Streuung
  • *6A die Checksumme (beginnt immer mit *)
darstellt.
Drum prüfe, wer sich ewig bindet

Zum ersten Aufwärmen lassen sich die GPS-Module von u-blox mit einer Windows-Software namens u-center[1] auslesen. Das ist insofern interessant, als sich dadurch die Funktion des GPS-Moduls veranschaulichen und prüfen lässt:

Wo bin ich?
Das kostenlose Programm u-center im Betrieb (Microsoft Windows only). Auf dem Fenster sind die empfangbaren Satelliten grün markiert

Um das Modul an einen USB-Port des PCs anzuschließen, bietet sich ein FTDI-USB-to-TTL-Adapter an:

Wo bin ich?
Zum direkten Anschluss des GPS-Empfängers an einen Computer, nutzt die Schaltung einen FTDI-Adapter (USB to TTL)

In der Schaltung existieren folgende Verbindungen:

FTDI TX mit NEO RX

FTDI RX mit NEO TX

FTDI Vcc mit NEO Vcc

FTDI GND mit NEO GND

Das USB-to-TTL-Adapterboard (FTDI) muss dabei auf 3,3V Betrieb gejumpert sein. Natürlich können Sie alternativ auch preisgünstige USB-TTL-Adapter mit Chipsets der Typen CP2102 oder CH340 nutzen, sofern Sie den entsprechenden Treiber installieren.

Nach Anschluss der Schaltung über USB (FTDI-Adapter) an den Windows-PC, und der Einstellung des verwendeten GPS-Produkts sowie des richtigen USB-Ports in u-center dauert es eine Weile bis der GPS-Empfänger Verbindungen zu genügend vielen Satelliten aufbauen konnte. Mindestens vier müssen es sein, wie bereits an anderer Stelle beschrieben. Danach ist die Position fixiert (fixed), eine grüne LED am NEO blinkt, und im Anwendungsfenster erscheinen die erfassten Satelliten und die festgestellte Position, nebst umfangreicher weiterer Information. Aus Platzgründen kann ich an dieser Stelle nicht auf die komplette Funktionalität der Software eingehen.

Schaltung mit Arduino

Für die Beispielsschaltung kommt ein Arduino Nano mit 5V-Logik zum Einsatz, der über die digitalen Pins D3 und D4 als Software-basierten seriellen Port mit dem GPS-Modul verbunden ist. Allerdings darf die Verbindung der beiden Komponenten nicht direkt erfolgen, da ein NEO 6M oder 7M Modul mit 3,3V-Logik arbeitet. Deshalb ist ein Logic-Level-Konverter nötig, der zwischen den beiden Logik-Welten adaptiert. Einige Maker im Internet halten den direkten Anschluss von GPS-Modul an den Arduino zwar für unproblematisch. Das mag kurzfristig gelten, aber bei langem Dauerbetrieb ist ein Abrauchen des GPS-Moduls definitiv nicht auszuschließen.

Folgende Zutaten (Bill of Material) sind notwendig, um die Schaltung aufzubauen:

  • Breadboard
  • Arduino Nano MCU
  • Logic Level Converter (zwischen 3,3V- und 5V-Logik) mit mindestens zwei Kanälen
  • GPS Modul wie z.B. NEO 6M oder 7M GPS
  • 10 Jumper Wires (male to male)
  • 2 Jumper Wires (male to female)
Wo bin ich?
In der Schaltung sind das GPS-Modul (links oben), der Logic Level Konverter (roter Baustein), der Arduino Nano (Mitte) und das FTDI-Board (rechts) zu sehen

Die Schaltung implementiert folgende Verbindungen:

  • Der FTDI-Adapter dient nur zur Versorgung des GPS-Empfängers mit Strom. Dementsprechend laufen von den Ausgängen VCC und GND des Adapters jeweils ein Kabel zu den entsprechenden Stromschienen am Breadboard.
  • Der RX-Eingang des GPS-Moduls wird über den Logic Level Konverter mit dem TX-Ausgang des Arduino Nano verbunden. Im Beispiel fungiert der digitale Pin D4 als TX-Ausgang des Arduino-Boards.
  • Der TX-Ausgang des GPS-Moduls wird über den Logic Level Converter mit dem RX-Eingang des Arduino Nano verbunden. Im Beispiel fungiert der digitale Pin D3 als RX-Eingang des Arduino Boards.

Noch ein Wort zum verwendeten Arduino-Board. Wer ein Board mit seriellen Hardwareports einsetzt wie zum Beispiel einen Arduino Mega, sollte einen seriellen Hardware-Port (Serial1, Serial2, Serial3, ...) für die Verbindung verwenden. Das ist die schnellste und beste Lösung.

Bei Boards wie Arduino Uno, Leonardo, Nano muss stattdessen eine Software-basierte Lösung zum Einsatz kommen, etwa die Standard-Lösung SoftwareSerial. Leider führt SoftwareSerial betriebsbedingt zu hohen Latenzzeiten und kann deshalb nur geringere Baudraten unterstützen. Das können Alternativen wie AltSoftSerial deutlich besser. Für die Geschwindigkeiten der GPS-Module von 4800 Baud oder 9600 Baud erweist sich aber SoftwareSerial als mehr mehr als ausreichend.

Das GPS-Modul zeigt eine grüne, blinkende LED sobald ihm genügend viele Satelliten für die Positionsbestimmung zur Verfügung stehen:

Wo bin ich?
Die Schaltung im Betrieb. Die grün blinkende LED zeigt an, dass der NEO-6m mit mindestens vier Satelliten in Kontakt steht
Programmierung

Es macht keinen Spaß, systemnah mit einem GPS-Modul beziehungsweise mit den Rohdaten im NMEA 183 Standardformat zu arbeiten. Daher existieren diverse Bibliotheken für Arduino, um diese Aufgabe zu erleichtern, darunter die Bibliotheken NEOGPS, GPS-NEO-6m-master und TinyGPSPlus. Eine Suche mit dem Begriff GPS im Menü der Arduino IDE unter Sketch > Include Library > Manage Libraries liefert die entsprechenden Bibliotheken.

Für den Artikel nutze ich TinyGPSPlus. Nach Installation von TinyGPSPlus lässt sich das Beispiel FullExample.ino über den Menüpfad File > Examples > TinyGPSPlus > FullExample öffnen.

Der Anfang des Sketches muss ein Programm den entsprechenden Header inkludieren:

#include 
#include ++.h>

Der Einfachheit halber benutzt der Sketch in unserem Fall SoftwareSerial. Ohnehin steht beim Arduino Nano kein eigener serieller Hardwareport für diesen Zweck zur Verfügung.

Die Pins des Nano-Boards für den Software-Port lauten im obigen Beispiel D3 (als RX) und D4 (als TX):

static const int RXPin = 3, TXPin = 4;
static const uint32_t GPSBaud = 9600;

// Das Objekt zum Zugriff auf die Bibliothek:

TinyGPSPlus gps;

// Software-basierter Serieller Port
SoftwareSerial ss(RXPin, TXPin);

Die Baudrate beträgt in dem von mir verwendeten NEO-6m-Modul 9600 Baud. Üblicherweise kommen auch 4800 Baud recht häufig vor. Dem Datenblatt Ihres GPS-Moduls sollten Sie daher den für Ihr Modul jeweils richtigen Wert entnehmen.

Im setup() des Sketches erfolgt die Verbindung mit dem integrierten seriellen Monitor (der für die Verbindung von PC/Mac mit dem Arduino-Board) über Serial.begin(), und die mit der emulierten seriellen Verbindung vom Arduino-Board zum GPS-Modul über ss.begin();

void setup()
{
Serial.begin(115200); // Serieller Monitor für print-Ausgaben
ss.begin(GPSBaud); // Serieller Software-Port zum GPS-Modul
// ...
}

Im eigentlichen Hauptprogramm loop() ist der Zugriff auf die vom GPS-Modul gelieferte Information möglich:

void loop()
{
while (ss.available() > 0) // Daten liegen an der Leitung an
if (gps.encode(ss.read())) // Lese Daten und enkodiere sie
{
... // Nutzung der gelesenen Daten
}

if (millis() > 10000 && gps.charsProcessed() < 10) // Timeout nach 10 secs
{
Serial.println(F("Kein GPS-Modul gefunden"));
while(true); // Fini, das Ende der Welt
}
}

Information lässt sich über die Variable gps auslesen:

gps.satellites.value() // falls gps.satellites.isValid()
gps.hdop.value() // falls gps.hdop.isValid()
gps.location.lat() // falls gps.location.isValid()
gps.location.lng() // falls gps.location.isValid()
gps.location.age() // falls gps.location.isValid()
gps.date // falls gps.date.isValid()
gps.time // falls gps.time.IsValid()
gps.altitude.meters() // falls gps.altitude.isValid()
gps.course.deg() // falls gps.course.isValid()
gps.speed.kmph() // falls gps.speed.isValid()

Das funktioniert immer nach dem selben Schema: Zuerst ist zu überprüfen, ob überhaupt ein gültiger Datenwert vorliegt wie zum Beispiel bei gps.location.isValid(). Ist dies der Fall, enthalten Variablen wie gps.location.lat() (= geographische Breite) gültige Werte.

Arduino IDE: Sketch, der TinyGPSplus nutzt
Das Bild zeigt die Arduino IDE und den seriellen Monitor. Auf den Arduino läuft ein Beispielsprogramm, das die TinyGPSPlus-Bibliothek mitliefert
Learning by Doing

Die unten abgedruckte Quelldatei beinhaltet ein sehr einfaches Beispiel, bei dem das Arduino-Board den seriellen Monitor zur Ausgabe nutzt und einen Software-emulierten Port zur Kommunikation mit dem GPS-Modul. In der Regel dauert es nach Inbetriebnahme des GPS-Moduls etwas bis es genügend Satelliten zur Positionsbestimmung lokalisieren konnte. Der Einfachheit halber geht die Demo-Anwendung davon aus, dass das Modul betriebsbereit ist und gültige Daten liefert (grüne LED blinkt).

In der Hauptschleife loop bestimmt das Programm in jeder Sekunde die Position, und gibt die entsprechende Information zeilenweise am seriellen Monitor aus.

Die Daten werden im CSV-Format (Comma Separated Values) ausgegeben. Dieses Format hat Vorteile, wenn Benutzerinnen später die Daten weiterverarbeiten wollen. Dazu unten mehr.

/*******************************************************
*
* Demo-Anwendung zur Nutzung eines GPS-Moduls des
* Typs u-blox NEO 6m oder 7m
* (c) Michael Stal, 2018
* frei verwendbar gemaess Creative Commons
*
*******************************************************/

#include ++.h>

#include

// Verwendete digitale Pins für SoftwareSerial
static const int RX = 3, TX = 4;
// !!! Baudrate des GPS-Moduls: Anpassung an eigene HW notwendig
static const uint32_t GPSBaud = 9600;

// Zugriff auf TinyGPS++ ueber gps
TinyGPSPlus gps;

// Emulierter Port zum GPS Geraet
SoftwareSerial gpsPort(RX, TX);

/*******************************************************
*
* setup baut alle Verbindungen auf
* zum seriellen Monitor und zum GPS-Modul
*
*******************************************************/

void setup()
{
// Verbindung zum seriellen Monitor
Serial.begin(115200);
// Verbindung mit GPS-Modul
gpsPort.begin(GPSBaud);

// Header Zeile ausgeben (Format ist .csv)
Serial.println();
Serial.println("utc_t, lat, lon, elevation");
Serial.println("#name, latitude, longitude, elevation");
}

/*******************************************************
*
* Im Hauptprogramm wird jede Sekunde die aktuelle
* Position vom GPS-Geraet gelesen inklusive
* Datum und Zeit, geo. Breite, geo. Laenge, Hoehe
*
*
*******************************************************/

void loop()
{
while (gpsPort.available() > 0) // Daten vorhanden?
if (gps.encode(gpsPort.read())) {
showPositionData(); // ja, dann Ausgabe am ser. Monitor
delay(1000); // 1 Sekunde warten
}

if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println("Fehler: GPS Modul nicht gefunden");
while(true);
}
}

/*******************************************************
*
* showPositionData liest die aktuelle Position
* und gibt die Daten als Zeile (im .csv-Format) aus
*
*******************************************************/

void showPositionData()
{
// Erst Datum ...
if (gps.date.isValid())
{
Serial.print(gps.date.month());
Serial.print("/");
Serial.print(gps.date.day());
Serial.print("/");
Serial.print(gps.date.year());
}

Serial.print(" ");

// ... und Zeit
if (gps.time.isValid())
{
if (gps.time.hour() < 10) Serial.print("0");
Serial.print(gps.time.hour());
Serial.print(":");
if (gps.time.minute() < 10) Serial.print("0");
Serial.print(gps.time.minute());
Serial.print(":");
if (gps.time.second() < 10) Serial.print("0");
Serial.print(gps.time.second());
}

// Jetzt 2D-Position als geo. Breite, Laenge
if (gps.location.isValid())
{
Serial.print(" , ");
Serial.print(gps.location.lat(), 6);
Serial.print(" , ");
Serial.print(gps.location.lng(), 6);
}

// Und dann noch Hoehe
if (gps.altitude.isValid())
{
Serial.print(" , ");
Serial.print(gps.altitude.meters(), 6);
}

Serial.println();
}

Die Ausgabe des Sketches am seriellen Monitor schaut bei einem sehr einfachen Beispiel wie folgt aus:

utc_t, lat, lon, elevation
#name, latitude, longitude, elevation
2/25/2018 14:33:06 , 48.126541 , 11.571980 , 523.500000
2/25/2018 14:33:07 , 48.126533 , 11.571964 , 523.500000
...
WYSIWYG

Statt auf dem Monitor könnte die obige Anwendung alle Positionsdaten auch als CSV-Datei (zum Beispiel auf einer SD-Card) speichern. In einem früheren Posting [2]hatte ich das dazu notwendige Vorgehen bereits beschrieben.

Dadurch können Maker die erzeugte Datei weiter verarbeiten, um die Tracking-Daten zum Beispiel in Google Earth oder Maps zu visualisieren.

Ein Programm von Format wie Google Earth erwartet allerdings .KML-Dateien (Keyhole Markup Language) oder .KMZ-Dateien. Woher also nehmen und nicht stehlen? Zum Glück gibt es genau zu diesem Zweck einen Online-Dienst namens GPS Visualizer[3].

Die obige Daten-Ausgabe des GPS-Empfängers habe ich in einer Datei arduinotrack.csv gespeichert und den Dienst GPS Visualizer dafür genutzt, um eine Google Map zu erzeugen.

Wo bin ich?
Der freie Online-Dienst GPS Visualizer erlaubt es, GPS-Daten von/nach verschiedenen Formaten zu konvertieren

Die erzeugte Map ist aber zugegebenermaßen eher unspektakulär, weil sich der Testaufbau immer an derselben Stelle meines Büros befunden hat:

Jetzt wissen die Leser wo ich wohne.
GPS Visualizer kann die Daten des GPS-Tracking z.B. über Google Earth oder Google Maps visualizieren
Fazit

In dieser Folge ging es um Ortung der aktuellen Position über GPS. Ein Microcontroller (MCU), in unserem Fall ein Arduino Nano, kommuniziert via serieller Leitung mit der verwendeten GPS-Hardware. Die Einsatzmöglichkeiten sind vielfältig, etwa die Steuerung einer Drohne, das Tracking eines Kraftfahrzeugs oder die Positionsbestimmung eines Containers, um nur einige Beispiele zu nennen.

Wer GPS in seinem Arduino-Projekt integrieren möchte, ist mit den preisgünstigen Komponenten wie dem NEO 6M oder 7M aus der Produktfamilie von u-blox bestens bedient.

Der weiter oben beschriebene Versuchsaufbau gibt lediglich die GPS-Daten aus. Es gibt wie immer unzählige Erweiterungsmöglichkeiten:

  • Mittels eines SD-Card-Shields könnte das Programm auch eine GPS-Datei erzeugen, beispielsweise im KML- oder GPX-Format, die sich über Webdienste wie Google Maps visualisieren lässt.
  • Für mobile Geräte sollte die Stromversorgung über Akkus oder Batterien erfolgen.
  • Statt eines Arduino-Boards bietet sich natürlich auch an, ein kompatibles Board zu nutzen wie ESP32, Teensy, oder STM32F103C8T6 . Diese Boards laufen unter 3,3V, sodass der im Beitrag benutzte Logic Level Konverter entfallen kann.

Jetzt bleibt mir nur noch, Ihnen viel Spaß beim Experimentieren zu wünschen.


URL dieses Artikels:
http://www.heise.de/-3976281

Links in diesem Artikel:
[1] https://www.u-blox.com/en/product/u-center-windows
[2] https://www.heise.de/developer/artikel/Spuren-hinterlassen-Datenlogging-mit-Arduino-3348205.html
[3] http://www.gpsvisualizer.com

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 26. Februar 2018 um 10:00

FreshRSS 1.10.0

Von Alkarex

Changelog:

  • API
  • Features
    • Ability to pause feeds, and to hide them from categories #1750
    • Ability for the admin to reset a user’s password #960
  • Security
    • Allow HTTP Auth login with REDIRECT_REMOTE_USER when using Apache internal redirect #1772
  • UI
    • New icons for marking as favourite and marking as read in the Reading View #603
    • Add shortcuts to switch views #1755
  • Bug fixing
    • Fix login bug when HTTP REMOTE_USER changes (used by YunoHost) #1756
    • Fix warning in PHP 7.2 #1739
  • Extensions
    • Allow extensions to define their own reading view #1714
  • I18n
  • Misc.
    • More sites in force-https.default.txt #1745
    • Trim URLs when adding new feeds #1778
  • 24. Februar 2018 um 12:03

MicroProfile unter der Lupe, Teil 3: JWT Security

Von heise online

zurück zum Artikel

Das Thema Security stellt in einer stark verteilten, Microservices-basierten Umgebung eine besondere Herausforderung dar. Im Umfeld von RESTful-Services hat sich in den letzten Jahren der auf OpenID Connect (OIDC) basierende Standard JSON Web Tokens (JWT) für rollenbasierte Zugriffskontrolle etabliert. Auf diesen Stack setzt auch die Spezifikation MicroProfile JWT RBAC Security (MP-JWT).

Ein Microservice kommt selten allein. Das ist kein Geheimnis, sondern Teil des Erfolgsrezepts. Ziel einer Microservice-basierten Architektur ist es, durch ein passendes Servicedesign, eine möglichst große Unabhängigkeit der einzelnen Services untereinander zu erreichen. Wie sieht es aber mit dem Thema Sicherheit aus? Gilt auch hier das Prinzip der größtmöglichen Unabhängigkeit? Und wenn ja, muss sich ein Client dann bei jedem Service oder gar bei jedem Service-Aufruf separat mit seinen User Credentials (z.B. Username und Passwort) authentifizieren und autorisieren?

JWT Quick Guide

Im Umfeld verteilter Services hat sich in den letzten Jahren der auf OpenID Connect basierende JSON-Web-Tokens-Standard [1] (siehe auch JWT.io Introduction [2]) als der Standard etabliert.

Vereinfacht gesprochen authentifiziert sich bei diesem Verfahren ein Client einmalig bei einem Authentication-Server (Issuer) und erhält im Gegenzug ein zeitlich begrenztes, personalisiertes und in der Regel signiertes Token (JWT mit JWS [3]). Personalisiert bedeutet in diesem Zusammenhang, dass das Security-Token sogenannte Claims enthält, also Key-Value-Paare, welche unter anderem . Informationen zu dem authentifizierten Nutzer (Subject) beinhalten.

Mit Hilfe des Tokens kann sich der Client nun gegenüber externer Services (Resource Server) mittels Bearer Authentication authentifizieren. Dazu schickt er einfach in jedem Request das Token im Authorization-Header mit:

GET /resource/123 HTTP/1.1
Host: openknowledge.com
Authorization: Bearer mF_9.B5f-4.1JqM

Dank Signatur können die aufgerufenen Services das Token auf Echtheit und Unverfälschtheit verifizieren. Da das Token Informationen über den Client enthält, sind die aufgerufenen Service zusätzlich in der Lage, eine rollenbasierte Zugriffskontrolle (RBAC; role based access control) – Autorisierung - durchzuführen.

Der Vorteil dieses Verfahrens liegt klar auf der Hand. Dank Token und den darin enthaltenen Informationen kann ein Service sowohl Authentifizierung als auch Autorisierung durchführen, ohne zusätzlich Informationen von einer dritten Partei wie einem User-Management oder Identity-Service erfragen zu müssen. Dies erspart unnötige Roundtrips. Dies gilt übrigens auch dann, wenn der aufgerufene Service einen weiteren Service aufruft (Service Chaining). In diesem Fall reicht der ursprünglich aufgerufene Service das Token inklusive der enthaltenen Nutzerinformation einfach im Request-Header weiter (Security Context Propagation).

MicroProfile und JWT

Seit Version 1.2 unterstütz auch das MicroProfile mit der Spezifikation MP-JWT 1.0 JWT-basierte Security. Die Spezifikation setzt dabei gleich an mehreren Punkten an und versucht folgende Aufgaben zu unterstützen:

  1. Token aus dem Request extrahieren,
  2. Token verifizieren und validieren,
  3. Claims des Token zugreifbar machen und
  4. JavaEE-Security-Context erzeugen und setzen.

Zu diesem Zweck definiert die MP-JWT Spezifikationen einen Satz von „non-optional“ Claims, also Pflichtfeldern, die ein spezifikationskonformes Token beinhalten muss:

  • typ: Header-Parameter für das Token-Format („JWT“)
  • alg: Header-Parameter für den Verschlüsselungsalgorithmus („RS256“)
  • kid: Header-Parameter mit Hinweis für die eindeutige Key ID
  • iss: Token-Issuer
  • sub: Subject des Tokens (Principle/User)
  • aud: angedachte Empfängergruppe
  • exp: Gültigkeit
  • iat: Ausstellungszeitpunkt
  • jti: eindeutiter Identifier
  • upn: eindeutiger Principle Name (für java.security.Principle)
  • groups: Liste von Gruppennamen für das Mapping mit Application-Roles

Ein minimales Beispiel eines MP-JWT in JSON-Format könnte wie folgt aussehen:

{ 
"typ": "JWT",
"alg": "RS256",
"kid": "abc-1234567890"
}
{
"iss": "https://auth.openknowledge.com",
"aud": "kNowLedGe",
"jti": "ok-12345",
"exp": 1311281970,
"iat": 1311280970,
"sub": "13579",
"upn": "lars.roewekamp@auth.openknowledge.com",
"groups": ["first-group", "second-group", "admin"],
}

Damit eine automatische Extraktion des Tokens aus dem Authorization-Header des Request erfolgen kann, muss der JAX-RS-Anwendung zunächst signalisiert werden, dass zur Authentifizierung und Autorisierung der MP-JWT JASPI (Java Authentication SPI for Containers) verwendet werden soll. Das erfolgt mit der Annotation LoginConfig aus dem Package org.eclipse.microprofile.jwt.


import org.eclipse.microprofile.auth.LoginConfig;

// Sets the authentication method to the MP-JWT for the MicroProfile JWT.
// The optional parameter realName is only needed, if authMethod
// is set to "BASIC" or for vendor specific configurations.
@LoginConfig(authMethod = "MP-JWT", realName="...")
@ApplicationScoped
@ApplicationPath("/myapi")
public class MyJaxrsApp extends Application { }

Anmerkung: Die Annotation LoginConfig wurde eingeführt, da das MicroProfile keinerlei Aussagen zu möglichen Deployment-Formaten trifft und somit auch nicht von dem Vorhandensein eines Servlet Containers bzw. einer web.xml ausgegangen werden kann. Ist eine web.xml vorhanden, kann alternativ zur Verwendung der Annotation auch der gleichnamige Eintrag login-config innerhalb der web.xml-Datei genutzt werden.

Die anschließende Verifizierung des Tokens erfolgt automatisch im Hintergrund. Zu diesem Zweck muss lediglich der Public Key des Token-Issuers in der Konfiguration des MicroProfile-Runtime-Container hinterlegt sein. Damit ein Token als gültiges MP-JWT angesehen wird, muss es zusätzlich mindestens die folgenden Bedingungen erfüllen:

  • JOSE (JavaScript Object Signing and Encryption) Header, der angibt, dass das Token via RS256 signiert wurde
  • iss-Claim, der denselben Token-Issuer beinhaltet, wie im MicroProfile-Runtime-Container konfiguriert

CDI Integration

Einmal extrahiert und verifiziert kann innerhalb des Microservice via CDI auf das Token beziehungsweise auf einzelne Claims des Tokens zugegriffen werden. Der Zugriff kann dabei via Raw-Typen, ClaimValue-Wrapper, javax.enterprise.inject.Instance oder JSON-P-Typen erfolgen:

@Path(/endpoint) 
@DenyAll
@RequestScoped
public class SomeEndpoint {

// 1) JWT object with @RequestScoped scoping
@Inject
private JsonWebToken callerPrincipal;

// 2) JWT as raw String
@Inject
@Claim(standard = Claim.raw_token)

private String rawToken;

// 3) IAT claim as Long value
@Inject
@Claim(standard=Claims.iat)

private Long issuedAt;

// 4) ISS claim as ClaimValue of type String
@Inject
@Claim(standard=Claims.iss)

private ClaimValue<String> issuer;

// 5) JTI claim as optional ClaimValue of type String
@Inject
@Claim(standard=Claims.jti)

private ClaimValue<Optional<String>> optJti;

// 6) JTI claim as JsonString
@Inject
@Claim(standard=Claims.jti)

private JsonString jsonJti;

// 7) custom claim "roles" as JsonArray
@Inject
@Claim("roles")

private JsonArray jsonRoles;

// 8) custom claim "customObject" as JsonArray
@Inject
@Claim("customObject")

private JsonObject jsonCustomObject;
...
}

Anmerkung: Die im obigen Listing gezeigte Klasse SomeEndpoint muss zwingendermaßen vom Scope @ReqiestScoped sein, das in ihr non-proxyable Typen (String und Long) aus dem Token injected werden.

Der aktuell angemeldete Caller bzw. das zugehörige Token kann mittels @lnject JsonWebToken mit dem Scope @RequestScoped injected werden (1). Das von Principal abgeleitete Interface JsonWebToken bietet eine Reihe von Convenient-Methoden, um gezielt und typenssicher auf die wichtigsten Claims des Tokens (Name, Issuer, Audience, Subject, TokenID, ExperiationTime, IssuedAtTime, Groups) zugreifen zu können.

Alternativ können die Claims aber auch direkt injected werden. Geschieht dies als non-proxyable Raw Typ, wie zum Beispiel String (2) oder Long (3), muss die umliegende Bean vom Scope @RequestScoped sein. Statt den Claim als Raw-Typen zu injecten, können alternativ auch ClaimValue- und/oder Optional-Wrapper verwendet werden (4 und 5). Und auch ein Zugriff via in JSON-P definierter Typen ist möglich (6, 7 und 8).

Um Tippfehler zu verhindern, sollte bei dem Zugriff auf Standard-Claims immer die Claims-Enumeration verwendet werden. Für den Zugriff auf Custom-Claims dagegen, können Strings oder eigene Enumerations genutzt werden.

JAX-RS Container Integration

Nachdem wir nun in der Lage sind, das JSON Web Token automatisch aus dem Request zu extrahieren und im Anschluss zu verifizieren, wäre es natürlich schön, wenn wir innerhalb der JAX-RS Ressourcen auf gewohnte JavaEE-Security-Mechanismen zurückgreifen könnten. Und auch das sieht die MP-JWT Spezifikation vor.

Ein Aufruf der Methode getUserPrinciple() der Klasse javax.ws.rs.core.SecurityContext liefert uns eine Instanz des aktuellen JsonWebToken zurück. Entsprechend können wir mit einem Aufruf der Methode isUserInRole(someRole) testen, ob die angegebene Rolle in dem Claim groups des Tokens enthalten ist oder nicht. Zusätzlich lässt sich mit Hilfe der Annotation @RollesAllowed(…) der Zugriff auf einzelne Methoden entsprechend der angegebenen Rolle(n) sperren bzw. freigeben.

Fazit und Ausblick

Wer schon einmal das „Glück“ hatte, die notwendigen Schritte zum Extrahieren, Validierung und Verifizieren eines JSON Web Tokens - inkl. der Überführung in einen JavaEE Security Context - implementieren zu dürfen, der weiß die Vorteile einer integrierten und standardisierten Lösung zu schätzen. Dies gilt insbesondere auch für die innerhalb des Tokens zu erwartenden Claims.

Das ganze Konzept steht und fällt allerdings damit, dass es am Ende hinreichend Identity Provider und Service Provider geben wird, die sich auf das MP-JWT Format einlassen. Um die Wahrscheinlichkeit zu erhöhen, hat man bei der Auswahl der „non-optional“ Claims bewusst darauf verzichtet, das Rad neu zu erfinden und stattdessen ein Subset von fünf der im IANA JWT Assignement [4] standardisierten Claims gewählt. Lediglich die zwei der "non-optional" Claims - upn (user principle name) und groups (Token Subject‘s Gruppen, welche auf JavaEE Security-Rollen gemappt werden) - sind proprietär.

Für zukünftige Versionen sind noch einige weitere Claims angedacht. So sollen mit Hilfe des Claims resouce_access servicespezifische Rollen angegeben werden können. Weiterhin wird darüber nachgedacht, neben dem bereits vorhanden Claim groups auch einen Claim roles einzuführen. Während groups dafür gedacht ist, dass die enthaltenen Werte auf das Rollenmodell der Ziel-Ressource gemappt werden, sollen die in roles enthaltenen Werte eins zu eins weitergereicht und in @RolesAllowed verwendet werden können.

Was ein wenig verwundert ist die Tatsache, dass die Art und Weise der Konfiguration, also zum Beispiel der Zurgiff auf den Public Key, den jeweiligen Runtime-Container-Herstellern überlassen wird, anstatt auf die MP Config API [5] zurückzugreifen. Entsprechende Überlegungen zur Vereinheitlichung gibt es aber bereits. Man darf gespannt sein.


URL dieses Artikels:
http://www.heise.de/-3973746

Links in diesem Artikel:
[1] https://tools.ietf.org/html/rfc7519
[2] https://jwt.io/introduction
[3] https://tools.ietf.org/html/rfc7515
[4] https://www.iana.org/assignments/jwt/jwt.xhtml
[5] https://www.heise.de/developer/artikel/MicroProfile-unter-der-Lupe-Teil-1-Config-API-3928886.html

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 20. Februar 2018 um 14:38

Technische Schulden entstehen einfach so

Von heise online

zurück zum Artikel

Kaum eine Metapher ist wichtiger für Softwareentwicklung als "technische Schulden". Aber sie hat leider einige Schwächen. Vor allem gehen Teams meistens die Schulden nicht bewusst ein.

Wie gut die Qualität des Codes einer Anwendung ist, können Benutzer oder Projektleiter kaum erkennen. Schließlich merken nur Entwickler, ob der Code besonders einfach geändert werden kann oder nicht. Leider ist das Spiel mit der Qualität aber gefährlich, denn schlechte Qualität bringt im Extremfall ein Projekt zum vollständigen Stillstand. Technische Schulden sollen als Metapher das Problem mit der Qualität besser vermittelbar machen. So können Benutzer oder Projektleiter besser verstehen, warum nicht jedes Feature schnell mal so implementiert werden sollte.

Wikipedia

Wikipedia[1] beschreibt technische Schulden folgendermaßen: Ein Team, das in einem Softwareprojekt ohne besondere Rücksicht auf die Qualität Code sofort in Produktion bringt, liefert erst mal schneller. Dafür baut das Team aber Schulden auf. Genau wie bei Geldschulden müssen Zinsen gezahlt werden: Die Produktivität sinkt, denn die schlechte Codequalität hält das Team auf. Diese Beschreibung passt gut zu der Metapher: Wer einen Kredit aufnimmt, baut Schulden auf, um sich etwas schneller zu kaufen und muss die Schulden später mit Zinsen zurückzahlen.

Ward Cunningham

Ursprünglich hat Ward Cunningham die Metapher der technischen Schulden aus der OOPSLA-Konferenz [2]1992 eingeführt. Er erklärt auf YouTube[3] den Begriff anders: Code repräsentiert immer das aktuelle Verständnis des durch die Software gelösten Problems. Wenn das Team Neues lernt, dann muss der Code durch Refactorings konsolidiert werden, sodass das Gelernte optimal repräsentiert ist. Wenn die Refactorings unterbleiben, entstehen technische Schulden und der Code ist schwieriger zu ändern. Cunningham schließt explizit aus, dass das Teams bei der Qualität Kompromisse macht und widerspricht damit eindeutig dem Wikipedia-Artikel. Das Team baut keine Schulden auf, sondern die Schulden entstehen unwillkürlich.

Martin Fowler

Martin Fowler hat eine andere Perspektive: Entweder das Projekt ist umsichtig (prudent) und trifft Entscheidungen über die Qualität oder es geht so rücksichtslos (reckless) vor, dass es die Qualität nicht beachtet. Außerdem geht das Team bewusst (deliberate) einen Qualitätskompromiss ein oder technische Schulden entstehen unbeabsichtigt (inadvertent). Aus den Eigenschaften umsichtig/ ücksichtlos auf der einen Seite und bewusst/unbeabsichtigt auf der anderen Seite entstehen vier Quadranten[4]. Der Wikipedia-Definition entspricht umsichtig/bewusst: Das Team kennt die Qualität (umsichtig) und trifft bewusst die Entscheidung, einen Qualitätskompromiss einzugehen. Cunninghams Erklärung ist umsichtig, weil das Team die Qualität kennt, aber die technischen Schulden entstehen nicht bewusst, sondern unbeabsichtigt, weil das Team lernt und der Code das Gelernte noch nicht abbildet.

Meiner Meinung nach gibt es noch eine weitere Quelle technischer Schulden: der technische Fortschritt. Neue Architekturen und Technologien machen das alte Vorgehen obsolet. Wenn der Code nicht passend aktualisiert wird, entstehen technische Schulden. Auch das ist unbeabsichtigt, weil es sich nicht verhindern lässt.

Wie mit technischen Schulden umgehen?

Das Wichtigste an technischen Schulden ist aber, wie man mit ihnen umgeht. Kein System ist perfekt. Es gibt immer etwas zu optimieren. Das bedeutet, dass Teams praktisch unbegrenzt optimieren können. Wenn das Team durch eine Optimierung keine Verbesserung der Produktivität erwartet, die mehr bringt, als die Optimierung an Aufwand kostet, dann sollte die Optimierung unterbleiben. Dafür können Investitionen[5] eine gute Metapher sein. Die Qualität ist kein Ziel an sich, sondern nur ein Mittel für bessere Produktivität. Auch bei diesem Vorgehen hat die Metapher der technischen Schulden einen Vorteil: Die Qualitätskompromisse können problematisch sein, weil sie für Benutzer oder Projektleiter nicht leicht zu erkennen sind und zum Stillstand des Projekts führen können. Der Begriff "technische Schulden" stellt genau das dar.

tl;dr

Technische Schulden sind eine Metapher für die Qualität in Softwareprojekten mit einigen Schwächen und unterschiedlichen Interpretationen. Am wichtigsten ist jedoch, wie Teams mit den technischen Schulden umgehen.


URL dieses Artikels:
http://www.heise.de/-3969279

Links in diesem Artikel:
[1] https://en.wikipedia.org/wiki/Technical_debt
[2] http://c2.com/doc/oopsla92.html
[3] https://www.youtube.com/watch?v=pqeJFYwnkjE
[4] https://martinfowler.com/bliki/TechnicalDebtQuadrant.html
[5] https://www.infoq.com/articles/no-more-technical-debt

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 14. Februar 2018 um 18:59

12 YouTube-Kanäle, die du 2018 nicht verpassen solltest

Von heise online

zurück zum Artikel

YouTube ist schon lange keine reine Unterhaltungsplattform mehr. Es gibt inzwischen auch eine Vielzahl hochwertiger Inhalte über Java, Java EE und allgemeinere Softwareentwicklungsthemen.

Ich schaue inzwischen immer häufiger kurze Trainingsvideos oder auch ganze Konferenzvorträge auf YouTube. Es gibt keinen einfacheren und komfortableren Weg von den Besten unserer Branche zu lernen.

Hier sind, in ungeordneter Reihenfolge, ein paar Kanäle die mir in den letzten Monaten durch die regelmäßige Veröffentlichung qualitativ hochwertiger Videos aufgefallen sind:

1. Java[1]

Oracles YouTube Kanal dürfte vielen Java-Entwicklern bereits durch die aufgezeichneten Vorträge der JavaOne bekannt sein. Das Team veröffentlicht außerdem Vortragsmitschnitte des JVM Language Summit und Interviews mit bekannten Größen aus der Java-Community.

2. Adam Bien[2]

Adam zeigt in seinen Videos, wie einfach, effizient und leichtgewichtig die Entwicklung mit Java EE sein kann. In seiner sehr sehenswerten monatlichen Fragestunde beantwortet er außerdem die Fragen seiner Zuschauer und Leser.

3. Thoughts on Java[3]

Wenn du JPA oder Hibernate in deinen Projekten einsetzt, solltest du den "Thoughts on Java"-Kanal kennen. Hier veröffentliche ich jede Woche zwei neue Videos, in denen ich zeige, wie du deine Persistenzschicht einfach und effizient implementieren kannst.

4. Devoxx[4]

Der offizielle Kanal der Devoxx veröffentlicht Vortragsmitschnitte der bekannten Devoxx- und Voxxed-Days-Konferenzen. Damit kannst du dir die besten Redner und interessantesten Vorträge direkt zu dir nach Hause holen.

5. vJUG[5]

Einfacher als bei der virtual Java User Group kann man nicht an einem JUG-Treffen teilnehmen. Mit regelmäßigen Livestreams, einer 24-stündigen Onlinekonferenz und einem Buchklub bietet der Kanal der vJUG jede Menge interessanter Inhalte.

6. Sebastian Daschner[6]

Auf seinem Kanal veröffentlicht Sebastian sehr interessante Videos zu Java EE sowie zur Steigerung der Entwicklerproduktivität.

7. InfoQ[7]

Das InfoQ-Team stellt auf seinem Kanal Vortragsmitschnitte zu verschiedenen Architektur- und Softwareentwicklungsthemen von den QCon-Konferenzen zur Verfügung.

8. NightHacking[8]

Wer sich für Interviews und Diskussionspanels zu verschiedenen Java-Themen interessiert, findet auf dem NightHacking-Kanal viele sehenswerte Videos.

9. GOTO-Konferenzen[9]

Die GOTO-Konferenzen zeichnen ebenfalls viele Vorträge auf und stellen diese auf ihrem YouTube-Kanal kostenlos zur Verfügung.

10. JetBrainsTV[10]

Der JetBrains-YouTube-Kanal bietet eine schöne Mischung aus Vortragsmitschnitten der KotlinConf, Webinaren zu verschiedenen Softwareentwicklungsthemen und Trainingsvideos zu ihren eigenen Entwicklungswerkzeugen.

11. Spring Developer[11]

Wer mit Spring arbeitet, sollte auch den Spring-Developer-Kanal kennen. Das Team von Pivotal veröffentlicht dort eine Vielzahl hochwertiger Konferenzvorträge, Webinare und Schulungsvideos.

12. SouJava[12]

Die brasilianische SouJava-Organisation bietet auf ihrem Kanal eine Mischung aus Interviews und Webinaren in englischer und portugiesischer Sprache.


URL dieses Artikels:
http://www.heise.de/-3937979

Links in diesem Artikel:
[1] https://www.youtube.com/user/java
[2] https://www.youtube.com/user/bienadam
[3] https://www.youtube.com/channel/UCYeDPubBiFCZXIOgGYoyADw
[4] https://www.youtube.com/channel/UCCBVCTuk6uJrN3iFV_3vurg
[5] https://www.youtube.com/user/virtualJUG
[6] https://www.youtube.com/channel/UCG21GE2Go3vkj7mrs675ysA
[7] https://www.youtube.com/user/MarakanaTechTV
[8] https://www.youtube.com/channel/UCT0bL2CQIk1eANeXk57mxaA
[9] https://www.youtube.com/user/GotoConferences
[10] https://www.youtube.com/user/JetBrainsTV
[11] https://www.youtube.com/user/SpringSourceDev
[12] https://www.youtube.com/channel/UCH0qj1HFZ9jy0w87YfMSA7w

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 23. Januar 2018 um 10:00

Microservices? Oder lieber Monolithen?

Von heise online

zurück zum Artikel

Microservices sind ein Hype. So dauert es nicht lange, bis sich die Kritiker melden und wieder zurück zu Monolithen wollen. Aber hilft das weiter?

Microservices teilen ein System in kleine, unabhängig deploybare Module auf. Die Alternative sind Deployment-Monolithen. Dann wird die gesamte Anwendung mit allen Modulen als Ganzes auf einmal deployt. Intern können Deployment-Monolithen aus Modulen wie Java-Packages, Namespaces oder Bibliotheken aufgebaut sein.

Aktuell ziehen Microservices Kritik auf sich, weil Microservice-System oft keine gute Struktur aufweisen. Aber Microservices definieren nur, wie die Struktur umgesetzt wird. Wie gut die Struktur ist, hängt nicht davon ab, ob die Module Microservices sind oder klassische Module. Domain-driven Design (DDD) und Bounded Context sind nützliche Techniken, um eine gute Struktur zu erreichen. Sie erleben dank Microservices gerade eine Renaissance. Wenn aus der Microservices-Diskussionein Fokus auf DDD und besser strukturierte Software entsteht, ist das schon ein wichtiger Erfolg – egal ob als Module Microservices genutzt werden oder nicht.

Monolithen: meistens schlecht strukturiert

Ausgerechnet Deployment-Monolithen als Lösung für schlecht strukturierte Systeme zu propagieren, erscheint mir aber widersinnig. Ich habe viele Reviews von Deployment-Monolithen erstellt. Die Strukturen der untersuchten Monolithen ließ fast immer zu wünschen übrig. Meine Erklärung: Zu leicht schleichen sich im Sourcecode unbeabsichtigte Abhängigkeiten zwischen Modulen ein. Die einzige Ausnahme ist, wenn im Projekt ein Architekturmanagement-Werkzeug genutzt wird oder andere Maßnahmen ergriffen werden, um die Modulgrenzen zu erzwingen. Das war aber nur bei wenigen von mir untersuchten Deployment-Monolithen der Fall.

Da Microservices eigene Sourcecode-Projekte haben und Schnittstellen zwischen den Microservices zum Beispiel als REST-Schnittstellen implementiert sind, schleichen sich bei Microservices Abhängigkeiten nicht so einfach ein. Schließlich muss man eine Abhängigkeit zu einem anderen Sourcecode-Projekt erzeugen und eine Schnittstelle bedienen. Das ist viel aufwendiger als beispielsweise die Nutzung einer Klasse aus einem anderen Java-Package. Die Aufteilung in Microservices unterstützt also das Einhalten der Modulgrenzen.

Wenn eine gute Struktur festgelegt worden ist, lässt sie sich mit Microservices umsetzen. Deployment-Monolithen erfordern weitere Maßnahmen, um die Struktur dauerhaft abzusichern.

Jenseits der Struktur

Es scheint so, als wäre von diesen beiden Alternativen ein Deployment-Monolith wegen der niedrigeren Komplexität die bessere Wahl. Nur ein System muss betrieben und ausgeliefert werden. Aber Microservices sind als Architekturansatz entstanden, um reale Probleme zu lösen:

  • Jeder Microservices lässt sich unabhängig deployen. Das Deployment eines einzelnen, kleinen Microservice ist einfacher und schneller als das Deployment eines vollständigen Deployment-Monolithen. Auch das Risiko sinkt, weil die Änderungen nur ein Microservice und damit ein Modul betreffen. Die Änderungen sind daher nicht so groß. Damit gibt es weniger Möglichkeiten für Fehler. Das Zurückrollen von Änderungen und Strategien wie Blue/Green Deployment oder Canary Releasing sind ebenfalls aufgrund der geringen Größe der Microservices einfacher als bei einem Deployment-Monolithen. Wenn Continuous Delivery für einen Deployment-Monolithen umgesetzte werden soll, lohnt es sich immer, zumindest eine teilweise Migration zu Microservices in Betracht zu ziehen, weil das die Komplexität der Continuous Delivery Pipeline erheblich reduzieren kann.
  • Es gibt Technologiefreiheit. Wenn ein System langfristig weiterentwickelt werden soll, dann steht irgendwann eine Migration auf eine aktuellere Technologie an. Bei einem Deployment Monolithen muss das gesamte System mit einem Schritt auf eine neue technologische Basis gestellt werden. Microservices lassen sich hingegen einzeln migrieren.
  • Wenn jeder Microservice von einem Team entwickelt wird, können die Teams unabhängig voneinander Microservices und damit neue Features deployen. Ebenso können sie weitgehend unabhängig voneinander technische Entscheidungen treffen. Diese Unabhängigkeit erlaubt es den Teams, sehr autonom zu arbeiten. Das ist gerade bei komplexen Projekten sehr willkommen, um Koordinationsaufwand zu sparen.

Letztlich stehen Microservices für eine konsequente Entkopplung der Module: Technische Entscheidungen oder Deployment sind auf ein Microservice begrenzt. Ebenso führt der Ausfall eines Prozesses nur zum Absturz eines Microservices. Zwischen Microservices können beispielsweise durch Firewall zusätzliche Sicherheitsbarrieren errichtet werden und sie können unabhängig voneinander skaliert werden. Es entsteht also eine Entkopplung bezüglich Technologien, Deployment, Ausfall und Sicherheit. Auch die softwaretechnische Entkopplung kann sehr weit gehen, wie ein früherer Blog-Post[1] gezeigt hat.

So unterstützen Microservices Entkopplung und damit ein Hauptziel von Modulen.

Mehr oder weniger Aufwand?

Natürlich führen Microservices zu einer erhöhten Komplexität beispielsweise bei Tests oder im Betrieb. Diese zusätzliche Komplexität muss gegen die bessere Modularisierung, die stärkere Entkopplung und das unabhängige Deployment aufgewogen werden. Schließlich ist es nur sinnvoll, einen Architekturansatz zu wählen, wenn er für das Szenario die einfachste Lösung darstellt. Ursprünglich sind Microservices erfunden worden, weil sie nicht nur eine einfach Lösung sind, sondern große Teams und schnelles Deployment nur so möglich waren.

Microservices von Anfang an als "zu komplex" auszuschließen ist dabei genauso wenig hilfreich, wie Deployment-Monolithen grundsätzlich zu verdammen. Und wichtig bleibt, nicht nur die Frage nach der Modularisierungstechnologie zu stellen, sondern vor allem die fachliche Aufteilung vernünftig umzusetzen.

tl;dr

Microservices und Deployment-Monolithen sind unterschiedliche Modularisierungsansätze. Sie haben Vor- und Nachteile und passen zu verschiedenen Szenarien. Noch wichtiger als der Modularisierungsansatz ist, dass Struktur der Software gut ist.


URL dieses Artikels:
http://www.heise.de/-3944829

Links in diesem Artikel:
[1] https://www.heise.de/developer/artikel/Microservices-lassen-Komplexitaet-verschwinden-3194643.html

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 19. Januar 2018 um 08:36

Effective Java - Pflichtlektüre für den professionellen Java-Entwickler

Von heise online

zurück zum Artikel

Das Warten hat ein Ende. Seit Ende letzten Jahres gibt es die 3. Auflage von Joshua Blochs Buch "Effective Java[1]". Die neue Auflage des in englischer Sprache erschienen Buchs umfasst nun auch Best Practices und Empfehlung für die mit Java 7, 8 und 9 eingeführten Features und Programmierparadigmen.

Kurzrezension

Bloch beschreibt in seinem Buch detailliert und gut verständlich, wann und wie verschiedene Java-Features eingesetzt werden sollten. "Effective Java[2]" sollte zur Pflichtlektüre eines jeden professionellen Java-Entwicklers gehören.

Wer sollte das Buch lesen

Jeder professionelle Java-Entwickler, der effizienten und wartbaren Code schreiben möchte.

Detaillierte Rezension

Es gibt viele gute Bücher über Java, die die verschiedenen Sprachfeatures erklären. Das ist aber bekanntlich nur der erste Schritt. Um effiziente und wartbare Anwendungen entwickeln zu können, muss man nicht nur die einzelnen Features kennen, sondern auch verstehen, wann und wie diese einzusetzen sind.

Dabei hat Joshua Bloch vielen Entwicklern, mich eingeschlossen, bereits mit den vorherigen Auflagen seines Buchs "Effective Java" geholfen. Seine hervorragenden Erklärungen verdeutlichen die Funktionsweise und Auswirkungen verschiedener Sprachfeatures und zeigen Best Practices für die Erstellung von leicht verständlichem und zukunftssicherem Code. Dies setzt er nun mit der 3. Auflage seines Buchs fort, das er für die Verwendung der mit Java 7, 8 und 9 eingeführten Paradigmen und Sprachfeatures aktualisiert hat. Insbesondere die Kapitel zum Design von Interfaces sowie der Verwendung von Generics und Lambdas sollten allen Entwicklern bekannt sein.

90 Items mit geballtem Java-Wissen

Während der vergangenen zwei Woche, habe ich das Buch vollständig gelesen und kann dies nur jedem empfehlen. Es war unterhaltsam und sehr lehrreich. Aber es gibt auch gute Nachrichten für alle, die nicht die Zeit haben, das ganze Buch auf einmal zu lesen. Blochs Buch ist in 90 Items unterteilt, die gezielte Ratschläge und Erläuterungen für spezifische Aufgaben und Sprachfeatures bieten. Die Items verweisen zwar aufeinander, können jedoch auch gut einzeln gelesen werden.

Durch die Unterteilung kann das Buch auch als Nachschlagewerk bei der täglichen Entwicklungsarbeit verwendet werden. Ich bin mir bereits jetzt sicher, dass ich in naher Zukunft die komplexere Items zu Lambdas und Generics noch das eine oder andere Mal lesen werde. Wie auch bereits die vorherige Auflage, wird die 3. Auflage von "Effective Java" mein Begleiter bei der Entwicklung komplexer Aufgaben und der Erstellung neuer APIs werden.

Die im Buch enthaltenen 90 Items sind thematisch in folgende Kapitel unterteilt:

  • Creating and destroying objects
  • Methods common to all objects
  • Classes and interfaces
  • Generics
  • Enums and annotations
  • Lambdas and Streams
  • Methods
  • General programming
  • Exceptions
  • Concurrency
  • Serialization

Einige Kapitel mögen auf den ersten Blick grundlegende Themen der Java-Entwicklung behandeln. Ich empfehle aber trotzdem, diese vollständig zu lesen. Auch mit mehr als 15 Jahren Erfahrung als Entwickler und Architekt habe ich aus jedem Kapitel neue Ideen und Erkenntnisse gewonnen.

Gerade deshalb möchte ich jedem professionellen Java-Entwickler die 3. Auflage[3] empfehlen.


URL dieses Artikels:
http://www.heise.de/-3937945

Links in diesem Artikel:
[1] https://www.amazon.de/Effective-Java-Joshua-Bloch/dp/0134685997/
[2] https://www.amazon.de/Effective-Java-Joshua-Bloch/dp/0134685997/
[3] https://www.amazon.de/Effective-Java-Joshua-Bloch/dp/0134685997/

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 16. Januar 2018 um 10:00

MicroProfile unter der Lupe, Teil 2: Health Check und Metrics API

Von heise online

zurück zum Artikel

Um ein verteiltes System verlässlich (a.k.a. reliable) zur Verfügung zu stellen, ist es wichtig, essenzielle Metriken zu monitoren. MicroProfile hat seit der Version 1.2 mit Health Check und Metrics gleich zwei passende APIs im Gepäck.

Microservice-Anwendungen zeichnen­ sich durch die Unabhängigkeit ihrer Services und einer damit verbundenen Verteiltheit des Gesamtsystems aus. Während bei einer klassischen Enterprise-Java-Anwendung ein Deployment-Artefakt in einem Server beziehungsweise einem Server-Cluster läuft und somit recht gut unter Kontrolle zu halten ist, setzt sich eine Microservice-Anwendung in der Regel aus einer Vielzahl von Services zusammen, die jeweils in eigenen Prozessen – zum Beispiel in Docker-Containern – laufen. Um ein solches Szenario in den Griff zu bekommen, sind ein ausgereiftes Monitoring zum Aufdecken aufkommender Problemsituationen sowie die automatisierte Reaktion auf die Ergebnisse des Monitorings notwendig.

Es kommt also nicht von ungefähr, dass das Eclipse-Projekt MicroProfile bereits in Version 1.2 entsprechend APIs zum Monitoren von Microservices in die Spezifikation aufgenommen hat: HealthCheck API, Metrcis APIs.

Warum aber gleich zwei APIs? Hätte denn eine nicht auch ausgereicht? Die beiden zur Verfügung stehenden APIs sprechen tendenziell unterschiedliche Bereiche des Monitorings an. Mithilfe der Health Check API[1] soll von außen festgestellt werden können, ob ein Service beziehungsweise eine Anwendung noch so läuft, wie geplant. Auf die einfache Frage "geht es dir gut?" bekommt der Anfragende ein genauso einfaches "Ja" oder "Nein" beziehungsweise die Statusmeldung "UP" oder "DOWN" als Antwort zurück. Diese Information lässt sich von Tools wie Kubernetes[2] nutzen, um den entsprechenden Service oder einzelne Komponenten des Service gezielt zu ersetzen oder zu beenden und im Anschluss neu zu starten. Die zweite API, Metrics API[3], dagegen dient dazu, gezielt Detailinformationen zum aktuellen "Gesundheitszustand" eines Service und dessen Verlauf abfragen zu können. Mithilfe von Langzeitmetriken lassen sich so zum Beispiel Wachstumspläne für die genutzte Infrastruktur aufstellen oder proaktiv auf sich abzeichnende Engpässe reagieren.

Erfinden wir hier das Rad nicht neu, wird sich jetzt der eine oder andere fragen? Wir haben doch bereits seit Jahren mit JMX und JSR 77 zwei mehr oder minder etablierte Standards im Enterprise-Java-Umfeld. Ja und nein. Insbesondere in einer per Definition als polyglott angelegten Welt – und das ist die Welt der Microservices – ist es wichtig, einen gemeinsamen und vor allem einfachen Standard für das Monitoren des Gesundheitszustandes der Services und das regelmäßige Abfragen von Metriken zu etablieren. Hierbei spielen, wie wir gleich noch sehen werden, Aspekte, wie ein standardisierter REST-Ressourcenpfad, einheitliche Datentypen oder aber auch die Definition der zu verwendenden HTTP Return-Codes eine wichtige Rolle.

Alles gesund und munter?

Mithilfe der Eclipse MicroProfile Health Check API soll die generelle Verfügbarkeit sowie der Status ("UP" oder "DOWN") einer MicroProfile-Instanz – also eines auf dem MicroProfile basierenden Microservices – geprüft werden können. Die API ist weniger für den manuellen Gebrauch als vielmehr für Szenarien im Umfeld von Container-basierten Umgebungen gedacht (M2M). So wundert es nicht, dass als Vorbild für die API proprietäre Lösungen, wie Cloud Foundry Health Check[4] oder Kubernetes Liveness and Readiness Probes[5], herangezogen wurden. Dank der Health Check API können Monitoring- und Managment-Tools durch einen einfachen GET-REST-Call des Endpoints /health automatisiert feststellen, ob ein Service wie gewünscht läuft oder gegebenenfalls ersetzt oder neu gestartet werden muss.

GET /health 

200 OK
{
"outcome" : "UP"
"checks": []
}

Besteht der Service aus mehreren Teilkomponenten, kann die Antwort des Service bei Bedarf noch weiter aufgeschlüsselt werden. Im folgenden Beispiel wird der Status des Customer REST Endpoints sowie der zugehörigen Datenbank separat durchgeführt.

200 OK 
{
"outcome": "UP",
"checks": [
{
"name": "datasource",
"state": "UP",
"data": {
"dbConnection": "...",
"dbName": "...",
"freeSpace": "..."
},
},
{
"name": "resources",
"state": "UP"
"data": {
"customers": "/customers",
"addresses": "/customers/{id}/addresses"
}
}]
}

Der aktuelle "Gesundheitszustand" des Service setzt sich in diesem Beispiel also aus zwei Komponenten zusammen. Nur wenn alle Checks den Status "UP" aufweisen, ist auch der Gesamtstatus des Services "UP", was mit einem HTTP-Status-Code 200 und entsprechender Payload quittiert wird. Andernfalls wird der Status von der Health Check API automatisch als "DOWN" interpretiert (HTTP-Status-Code 503). Konnte der gewünschte Gesundheits-Check aus irgendwelchen Gründen nicht durchgeführt werden, wird dies der aufrufenden Partei mit dem HTTP-Status-Code 500 signalisiert. In diesem Fall gilt der Status des Service als unbestimmt.

Die Implementierung und Einbindung der eben gezeigten Checks in den eigenen Microservice ist denkbar einfach. Die Health Check API stellt für diese Aufgabe sowohl ein entsprechendes Interface – HealthCheck – als auch eine Annotation - @Health - zur Verfügung.

@Health
@ApplicationScoped
public class ResourcesHealthCheck implements HealthCheck {

public HealthCheckResponse call() {
return HealthCheckResponse
.named("resources")
.withData("customers","/customers" )
.withData("addresses","/customers/{id}/addresses" )
.state(checkCustomersResource()
&& checkAddressesResource ())
.build();
}

private boolean checkCustomersResource() { return … }

private boolean checkAddressesResource() { return … }

Die Annotation werden im Kontext von CDI automatisch erkannt und die entsprechenden Beans beziehungsweise deren call()-Methoden aufgerufen, sobald ein externer Aufruf des /health-Endpoints auf dem Service erfolgt.

Mehr Details, bitte

Was aber, wenn wir nicht nur wissen wollen, ob ein Service ordnungsgemäß läuft oder eben nicht? Was, wenn uns zum Beispiel die aktuelle CPU- oder Speicherauslastung oder aber die Anzahl der derzeit verwendeten Threads interessiert? Und was, wenn wir aus historischen Daten und deren aktuellen Pendants Rückschlüsse darauf treffen möchten, wie sich unser Systemzustand entwickelt, um so zum Beispiel bei Bedarf mehr Plattenplatz zur Verfügung zu stellen oder neue Service-Instanzen zu starten beziehungsweise bestehende Instanzen zu stoppen.

Die MicroProfile Metrcis API bietet eine genormte und individuell erweiterbare Schnittstelle zur Beantwortung genau dieser Fragestellungen – und vieler anderer mehr. Mithilfe eines REST-Calls gegen den Endpoint /metrics beziehungsweise einen von drei untergeordneten Metrik-Scopes (Sub-Ressourcen: base, vendor, application) lassen sich die gewünschten Telemetrie-Daten via HTTP abfragen und über Tools, wie Prometheus[6], automatisch auswerten, um so im Anschluss entsprechende Aktionen anzustoßen.

Die Rückgabe erfolgt dabei entweder im JSON-Format, bei Angabe des Accept-Headers "application/json" oder alternativ im Prometheus Text Format (bei fehlendem Accept-Header). Es ist davon auszugehen, dass zukünftig noch weitere Formate durch die Spezifikation oder aber durch herstellerspezifische Erweiterungen unterstützt werden.

Bei dem ersten Scopes – base – handelt es sich um Telemetriedaten, die jede MicroProfile-Implementierung beim Aufruf des allgemeinen Endpoints /metrics beziehungsweise des Scope-spezifischen Endpoints /metrics/base zur Verfügung stellen muss. Hier finden sich hauptsächlich JVM-relevante Informationen:

GET /metrics/base
Accept: application/json
Authorization: Basic ....

200 OK
{
"classloader.totalLoadedClass.count": 12595,
"cpu.systemLoadAverage": 3.88525390625,
"gc.PSScavenge.time": 262,
"thread.count": 30,
"classloader.currentLoadedClass.count": 12586,
"jvm.uptime": 4795005,
"memory.committedHeap": 740818944,
"thread.max.count": 46,
"cpu.availableProcessors": 4,
"gc.PSMarkSweep.count": 3,
"thread.daemon.count": 28,
"classloader.totalUnloadedClass.count": 9,
"gc.PSScavenge.count": 13,
"memory.maxHeap": 3817865216,
"cpu.processCpuLoad": 0.00571799781527977,
"memory.usedHeap": 238923968,
"gc.PSMarkSweep.time": 448
}

Anmerkung: Wie der Beispielaufruf zeigt, geht die Spezifikation davon aus, dass der /metrics-Endpoint in irgendeiner Weise abgesichert werden kann. In welcher Art und Weise dies passiert, ist aktuell nicht spezifiziert und somit dem jeweiligen Hersteller überlassen.

Zusätzlich zu diesen universellen Metriken hat jeder Hersteller optional die Möglichkeit, eigene, in der Regel nicht portable Metriken via /metrics beziehungsweise /metrics/vendor anzubieten. Dies könnten zum Beispiel Informationen zum Zustand eines intern verwendeten Cache oder eines Messaging-Systems sein.

Besonders interessant, aus Sicht eines Microservices-Entwicklers, ist der dritte und letzte Scope: application. Auch dieser Scope ist optional und kann zur Bereitstellung von anwendungsspezifische Metriken genutzt werden.

Im folgenden Beispiel kann die Anzahl an Einschreibungen sowie die jeweils für die Einschreibungen benötigte Zeitspanne als Metrik abgefragt werden. Das Beispiel zeigt ebenfalls, dass sich, je nach gewählter Metrik, neben den aktuellen Werten auch Durchschnitts- und Trendwerte abfragen lassen:

GET /metrics/application
Accept: application/json
Authorization: Basic ....

200 OK
{
"microprofile.demo.subscriptions": 6,
"microprofile.demo.doSubscribe": {
"fiveMinRate": 0.18984199379480962,
"max": 1949047687,
"count": 6,
"p50": 901908241,
"p95": 1949047687,
"p98": 1949047687,
"p75": 1909288320,
"p99": 1949047687,
"min": 423270500,
"fifteenMinRate": 0.19664645980623557,
"meanRate": 0.12968582020280628,
"mean": 1164575631.8269844,
"p999": 1949047687,
"oneMinRate": 0.148852445426026,
"stddev": 589520048.3135717
}
}

Der Abfrage von Metriken mittels Metrics API kann auf drei unterschiedlichen Ebenen erfolgen:

  1. GET /metrics: liefert alle Metriken für alle Scopes
  2. GET /metrics/: liefert alle Metriken für den angegebenen Scope
  3. GET /metrics//: liefert die Metrik für den angegebenen Namen und Scope

Jede Metrik ist optional mit einer Reihe von Metadaten verbunden. Sie sollen aufrufenden Tools, aber auch Menschen (Operators) dabei helfen, die gelieferten Wert besser interpretieren zu können. Neben Informationen wie description und displayName sind vor allem die beiden Metadaten type (counter, gauge, meter, timer, histogram) und unit von besonderem Interesse.

Welche Metadaten einer Metrik zugeordnet sind, lässt sich leicht erfragen, indem statt eines GET- ein OPTIONS-Request gegen den entsprechenden REST-Endpoint abgesetzt wird.

Während die Metadaten bei den Scopes base von der Spezifikation vorgegeben sind, können sie bei den beiden anderen Scopes – vendor und application – frei zugeordnet werden.

Gezielte Abfragen via Tags

In dynamischen Welten, wie denen der Microservices, spielen Label beziehungsweise Tags eine besondere Rolle. Während sich die ID eines Service durch automatisches (Re-)Deployment ändern kann, können eindeutige Tags als gemeinsamer Aufhänger für gezielte Abfragen von Metriken durch Tools, wie Kubernetes und Prometheus, genutzt werden. So wäre es zum Beispiel denkbar, dass man die Metriken einer bestimmten Anwendung (app=myApp) oder alternativ einer bestimmten Schicht einer Anwendung (app=myApp && tier=database) abfragen und visuell darstellen beziehungsweise verdichtet auswerten möchte.

Damit dies möglich wird, erlaubt die Metrics API die Angabe von Tags. Dies kann entweder mithilfe der MicroProfile Config API [7]und dem Key MP_METRIC_TAGS geschehen oder alternativ über das Application Metrics Programming Model erfolgen.

Application Metrics Programming Model

Die Metrics API erlaubt es, neben den allgemeinen und herstellerspezifischen Metriken auch eigene, anwendungsspezifische Metriken im Scope application zu registrieren. Dies sind genau diejenigen Metriken, die bei einem Aufruf von /metrics/application zurückgeliefert werden.

Zur einfachen Handhabung gibt es für jeden Metrik-Typen eine eigene Annotation (@Counted, @Gauge, @Metered, @Metric, @Timed), die je nach Typ auf Klassen, Konstruktoren, Methoden oder Parametern angewandt werden können.

Das folgende Beispiel zeigt eine REST-Ressource zum Einschreiben in beziehungsweise Ausschreiben aus einem Online-Kurs. Mittels Metric API lässt sich die Anzahl der aktuellen Einschreibungen sowie Telemetrie-Daten zur dafür benötigten Zeit abfragen. Das Resultat des Aufrufs haben wir bereits weiter oben gesehen:

@Path("subscriptions")
public class SubscriptionResource {

@Inject
@Metric
(absolute = true,
name = "microprofile.demo.subscriptions",
description = "number of subscriptions ",
displayName = "current subscriptions for online course",
unit = MetricUnits.NONE)
Counter subscriptionCounter;

@POST
@Produces(MediaType.APPLICATION_JSON)
@Timed(absolute = true,
name = "microprofile.demo.doSubscribe",
displayName = "Subscription time",
description = "Time of subscription in ns",
unit = MetricUnits.NANOSECONDS)
public Response subscribe(...) {
// subscribe to online course
...
subscriptionCounter.inc();
return Response.ok()… build();
}

@DELETE
@Produces(MediaType.APPLICATION_JSON)
@Timed(absolute = true,
name = "microprofile.demo.doUnsubscribe",
displayName = "Unsubscription time",
description = "Time of unsubscription in ns",
unit = MetricUnits.NANOSECONDS)
public Response unsubscribe() {
// unsubscribe to online course
...
subscriptionCounter.dec();
return Response.ok()… build();
}
}

Wer jetzt denkt, dass ihm das Ganze bekannt vorkommt, der hat wahrscheinlich recht. Die Macher der Metrics API haben bewusst versucht, das Rad nicht neu zu erfinden und sich stattdessen an der etablierten DropWIzard Metrics API orientiert.

Wie das Beispiel zeigt, ist die Wahl des Metriknamens (name = "...") nicht ganz unwichtig. Und dies gilt gleich in zweierlei Hinsicht. Zum einen erleichtert die Wahl eines geeigneten Namens inklusive eindeutigem Namensraum, das gezielte Abfragen und Filtern von Metriken durch angebundene Tools enorm. Zum anderen verhindern versehentlich doppelt vergebene Namen das Deployment eines Microservices, da CDI dies zum Zeitpunkt des Scannings feststellt und eine IllegealArgumentException wirft. Eine Ausnahme ist nur dann erlaubt, wenn eine Metrik bewusst mit dem Attribut reusable markiert wird. In diesem Fall müssen aber alle Varianten vom selben Typ sein.

Fazit

Um ein verteiltes System verlässlich (a.k.a. reliable) zur Verfügung zu stellen, ist es wichtig, essenzielle Metriken zu monitoren. MicroProfile hat seit der Version 1.2 mit Health Check und Metrics gleich zwei passende APIs im Gepäck. Während die Health Check API lediglich die Frage nach dem allgemeinen Gesundheitszustand eines Service klärt ("UP" oder "DOWN"), lassen sich dank Metrics API Rückschlüsse auf die allgemeine Entwicklung des Service und seiner Umgebung anstellen und so proaktiv auf Tendenzen, wie die negative Entwicklung von Speicherverbrauch oder Antwortzeiten, reagieren.

Metrics unterstützt als Austauschformat zur Anbindung von Monitoring- und Management- Tools sowohl JSON und auch das Prometheus Text Format[8]. Über weitere Formate wird bereits nachgedacht. Man darf gespannt sein.


URL dieses Artikels:
http://www.heise.de/-3940913

Links in diesem Artikel:
[1] https://github.com/eclipse/microprofile-health
[2] https://kubernetes.io
[3] https://github.com/eclipse/microprofile-metrics
[4] https://docs.cloudfoundry.org/devguide/deploy-apps/healthchecks.html
[5] https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes
[6] https://prometheus.io
[7] https://www.heise.de/developer/artikel/MicroProfile-unter-der-Lupe-Teil-1-Config-API-3928886.html
[8] https://prometheus.io/docs/instrumenting/exposition_formats

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 15. Januar 2018 um 12:56
  • 11. Januar 2018 um 20:11
  • 11. Januar 2018 um 20:11
  • 11. Januar 2018 um 20:10

Hibernate-Tipps: Einfache Möglichkeiten zur Abbildung nativer Abfrageergebnisse auf Entitäten

zurück zum Artikel

Die Hibernate-Tipps-Serie bietet schnelle und einfache Lösungen zu verbreiteten Hibernate-Fragen. Dieses Mal geht es um Ergebnisse komplexer Abfragen und deren Abbildung auf managed Entitäten.

Frage:

Ich musste meine Abfrage als native SQL Abfrage[1] implementieren, da sie zu komplex für JPQL[2] ist. Gibt es eine Möglichkeit das Abfrageergebnis auf Entitäten abzubilden, ohne diese separat laden zu müssen?

Lösung:

Wenn die Abfrage alle von der Entität abgebildeten Datenbankspalten selektiert, gibt es 2 Möglichkeiten das Ergebnis auf Entitäten abzubilden:

  1. Wenn die Ergebnismenge dieselben Spaltennamen verwendet wie die durch die Entität abgebildete Datenbanktabelle, kann eine einfache, implizite Abbildung verwendet werden.
  2. Wenn die Spaltennamen der Ergebnismenge von denen der Datenbanktabelle abweichen, muss eine explizite Abbildung definiert werden.
Implizite Abbildung von Abfrageergebnissen

Für die meisten Abfragen stellt eine implizite Umwandlung des Abfrageergebnisses die einfachste und schnellste Lösung dar. Dazu muss lediglich die Klasse der selektierten Entität als zusätzlicher Parameter an die createNativeQuery Methode übergeben werden.

Book b = (Book) em.createNativeQuery("SELECT * FROM book b WHERE id = 1",
Book.class).getSingleResult();

Der EntityManager verwendet dabei die für die Entität definierten Abbildungen der Spaltennamen auf deren Eigenschaften. Daher müssen die Spaltennamen der Ergebnismenge der nativen Abfrage den Spaltennamen der durch die Entität abgebildeten Datenbanktabelle entsprechen.

Explizite Abbildung von Abfrageergebnissen

Wenn die Spaltennamen des Abfrageergebnisses von denen der Tabelle abweichen, kann eine explizite Abbildung mit Hilfe einer @SqlResultSetMapping Annotation definiert werden.

@SqlResultSetMapping(
name = "BookMapping",
entities = @EntityResult(
entityClass = Book.class,
fields = {
@FieldResult(name = "id", column = "id"),
@FieldResult(name = "version", column = "version"),
@FieldResult(name = "title", column = "title"),
@FieldResult(name = "publishingDate",
column = "publishingDate"),
@FieldResult(name = "publisher", column = "publisherid")}))

Dabei muss der Name, über den das Mapping später referenziert werden kann, und eine @EntityResul-Annotation angegeben werden. Die @EntityResult-Annotation spezifiziert, welche Klasse für jeden Datensatz instanziiert werden soll und beschreibt über eine Liste von @FieldResult-Annotationen wie die Spalten des Ergebnisses auf die Eigenschaften der Entität abgebildet werden.

Um diese Abbildung zu verwenden, muss dann lediglich der im @SqlResultSetMapping definierte Name als 2. Parameter an die createNativeQuery-Methode übergeben werden.

em.createNativeQuery("SELECT * FROM book b WHERE id = 1", 
"BookMapping").getSingleResult();

Auf diese Art und Weise kann das Ergebnis einer nativen SQL Abfrage auch auf mehrere Entitäten[3] oder auf nicht durch den Persistenzkontext verwaltete POJOs[4] abgebildet werden.

Hibernate Tips – das Buch

Mehr als 70 solcher Rezepte zu Themen wie einfache und komplexe Mappingdefinitionen, Logging, Unterstützung von Java 8, Caching sowie die statische und dynamische Erzeugung von Abfragen gibt es in meinem Buch "Hibernate Tips: More than 70 solutions to common Hibernate problems". Es ist als Taschenbuch und E-Book auf Amazon[5] und als PDF auf hibernate-tips.com[6] erhältlich.


URL dieses Artikels:
http://www.heise.de/-3937917

Links in diesem Artikel:
[1] https://www.thoughts-on-java.org/jpa-native-queries/
[2] https://www.thoughts-on-java.org/jpql/
[3] https://www.thoughts-on-java.org/result-set-mapping-complex-mappings/
[4] https://www.thoughts-on-java.org/result-set-mapping-constructor-result-mappings/
[5] https://www.amazon.de/Hibernate-Tips-solutions-common-problems/dp/1544869177
[6] http://www.hibernate-tips.com/

Copyright © 2018 Heise Medien

Let's block ads! (Why?)

  • 10. Januar 2018 um 17:14
❌