/ Software-Entwicklung / Der Pragmatische Architekt: Nicht nur für Arduino Yún-ger

Der Pragmatische Architekt: Nicht nur für Arduino Yún-ger

Gerfried Steube on November 27, 2016 - 7:05 am in Software-Entwicklung

In diesem Blog war bislang von einfachen Microcontroller-Boards wie Arduino Uno und Mega, von verwandten Boards wie Teensy und von der ATtiny-Familie die Rede. Gelegentlich benötigen Entwickler allerdings mehr Power, ohne das Arduino-Ökosystem verlassen zu wollen. Was tun?

Natürlich ließe sich für diesen Zweck ein Raspberry Pi plus Gertboard verwenden. Das ist technisch interessant, weil das Gertboard auf dem ATmega 328p basiert. Preislich macht dieser Ansatz nur bei Projekten Sinn, die die zahlreichen Features des Raspberry Pi auch wirklich nutzen können.

Arduino Yún besteht aus einer Symbiose des ATmega32u4, der auch beim Leonardo-Board verbaut ist, und dem Atheros AR9331, der einer [email protected] folgt, und auf dem Embedded Linux läuft.

Ein Yun-Board von oben betrachtet
Ein Yún-Board von oben betrachtet Vergrößern
Bild: sparkfun.com

Unter der Haube

Zunächst soll der Blick auf das fallen, was sich unterhalb der Motorhaube befindet. Im Arduino Yún schlummern zwei Persönlichkeiten. Da ist zum einen ein Arduino-Board und zum anderen ein Embedded-Linux-Subsystem. Zusätzlich existiert eine sogenannte Bridge, die beide Welten miteinander verbindet.

AR9331-basiertes Linux-Subsystem:

  • Der AR9331-Prozessor arbeitet mit 3,3 V Spannung.
  • Die Größe des RAM beträgt 64 MByte (DDR2), die des Flash-Speichers 32 MByte.
  • Es enthält einen Ethernet-Anschluss mit Unterstützung von IEEE 802.3 bei Geschwindigkeiten von 10 oder 100 Mbit/s.
  • Auch WiFi-Unterstützung (IEEE 802.11 b/g/n) ist mit an Board.
  • Yún hat des Weiteren einen USB-2.0-Typ-A-Anschluss.
  • Für die Erweiterung des verfügbaren Dateisystems oder zum Verarbeiten von Daten gibt es einen Micro-SD-Karteneinschub.

ATmega32u4-basiertes Arduino-Subsystem:

  • Yún integriert ein Leonardo-Board mit 5 V Betriebsspannung.
  • Als “Antrieb” dient eine mit 16 MHz getaktete ATmega32u4-MCU.
  • Neben 32 KByte Flash-Speicher (abzüglich 4 KB für den Bootloader) stehen 2,5 KByte SRAM und 1 KByte EEPROM zur Verfügung.
  • Von den 20 digitalen Pins besitzen sieben die Fähigkeit zur Pulsweitenmodulation (PWM). Dazu existieren zwölf analoge Eingänge. An jedem Ein-/Ausgabe-Port lassen sich Stromstärken von 40 mA Stromstärke nutzen. Am 3,3-V-Ausgang sind es 50 mA.

arduino.cc
Das Yún-Board bietet eine Reihe von Anschlüssen und Komponenten Vergrößern
Bild: arduino.cc

Zwischen Linux- und Arduino-Subsystem existiert die Bridge-Hardware/Software, die eine Kommunikation zwischen beiden Subsystemen ermöglicht. Dazu später mehr.

arduino.cc
Die Brücke zwischen Arduino und Embedded Linux heißt Bridge Vergrößern
Bild: arduino.cc

Arduino Leonardo im Vergleich zum Uno

Den Leonardo hatte der Blog schon ein paar Mal adressiert, aber nicht weiter erläutert. Da das Yún-Board ein Leonardo-Board enthält, soll sich das jetzt ändern. Interessant sind an dieser Stelle vor allem die Unterschiede zwischen Uno und Leonardo.

Arduino Leonardo hat in seinem ATmega32u4-Microcontroller bereits eine (Micro-)USB-Schnittstelle integriert, weshalb zum einen der dafür vorgesehene ATmega16u2 des Uno entfallen kann, und zum anderen sich die Pins 0 und 1 (UART) nicht mehr für die serielle Kommunikation als notwendig erweisen. Daher benötigt ein Leonardo in der Regel kein SoftSerial mehr. Stattdessen verläuft die standardmäßige serielle Kommunikation fürs Debuggen (Serial) über USB, während sich die digitalen Pins 0 und 1 als zusätzlicher UART-Port Serial1 nutzen lassen.

Wegen der integrierten USB-Unterstützung lässt sich ein Leonardo am Windows/Linux/Mac-PC als USB-Gerät nutzen, auf Wunsch sogar als virtuelle Tastatur oder Maus.

Leonardo und Uno besitzen die gleiche Zahl von Pins, von denen der Maker 7 statt 6 für analogen und digitalen WM (Pulsweitenmodulation) nutzen kann. Alle 20 Pins sind als digitale Ein-/Ausgänge einsetzbar, 12 davon als analoge Eingänge. Aufgrund der identischen Lage der jeweiligen Pins sind Shields gleichermaßen für Uno und Leonardo nutzbar.

Ein Nachteil ist das unter Umständen etwas komplexere Handling des Leonardo, der öfters Zicken machen kann als dies beim Uno der Fall ist.

Arduino Yún Shield

Eine preisgünstige Alternative zum Arduino Yún ist der Erwerb eines Arduino Yún Shield. Dieses besteht aus dem Yún ohne Arduino-Subsystem. Zum Betrieb des Shields mit Arduino-Funktionalität ist daher ein zusätzliches Arduino-Board notwendig. Es lässt sich huckepack beispielsweise auf Arduino Uno, Mega, Leonardo aufstecken, aber auch mit einem anderen Board wie den Teensy-Platinen kombinieren. Ein System mit Yún Shield hat dadurch zwar einen größeren Formfaktor, ist dafür aber flexibler nutzbar.

Arduino Yun-Shield
Arduino Yún-Shield
Bild: arduino.cc

Preisgünstige kompatible Shields gibt es aus chinesischer Produktion unter Namen wie Dragino oder iduino Yún Shield für Preise unter 30 Euro (z. B. bei exp-tech). Das ist wohlgemerkt deutlich preisgünstiger als die meisten WiFi-Shields.

Das Dragino Yun Shield v2.4
Das Dragino Yún Shield v2.4 Vergrößern

Weil wir schon bei Preisen sind. Für den Arduino Yún wandern mehr als 70 Euro über den virtuellen Ladentisch. Daher ist die Shield-Option die klar günstigere Alternative. Der Autor besitzt neben einem Original-Yún-Boards der ersten Stunde ein Dragino Yún Shield mit neuester Version v2.4. Bei den kompatiblen Shields empfiehlt sich der Einsatz der neuesten Versionen. Bei älteren Versionen müssen zwei Pins von Arduino Uno/Mega per Jumper kurzgeschlossen werden, was bei den neueren Shields nicht mehr der Fall ist.

Das kompatible Arduino Yun Shield im Einsatz. Hier läuft gerade Beispiel 4 (siehe weiter unten im Artikel)
Das kompatible Arduino Yún Shield im Einsatz. Hier läuft gerade Beispiel 4 (siehe weiter unten im Artikel) Vergrößern

Noch ein Hinweis zur Stromversorgung von Shields: Bei Yún Shields erfolgt die Stromversorgung über das Arduino-Host-Board (VIN). Da das Yún Shield bis zu 200 mA benötigt, empfiehlt es sich, unbedingt das verwendete Arduino-Host-Board über ein Netzteil zu versorgen anstatt über USB eines Computers. Ansonsten könnten Probleme durch Überhitzung auftreten. Das Netzteil sollte dabei zwischen 7 V und 15 V Spannung liefern.

Konfiguration des Yún

Beim ersten Booten erzeugt das Yún Shield als Access Point ein WiFi-Netzwerk. Danach verbinden Maker ihr WiFi-Gerät wie Tablet, Smartphone, Notebook oder PC mit diesem Netzwerk. Auf demselben Gerät ist nun je nach Shield im Browser z.B. http://arduino.local oder http://dragino.local einzugeben, worauf eine Konfigurationsseite erscheint.

Zunächst muss sich der Benutzer freilich beim System anmelden. Das anfangs definierte Passwort heißt je nach Shield zum Beispiel arduino, iduino oder dragino.

Login-Dialog der Konfiguration
Login-Dialog der Konfiguration Vergrößern

Nach erfolgreichem Einloggen zeigt der Konfigurationsdienst die augenblicklichen Einstellungen. Hier zum Beispiel bei einem bereits konfigurierten Shield:

Nach dem Login zeigt der Konfigurationsdienst die aktuelle Konfiguration an
Nach dem Login zeigt der Konfigurationsdienst die aktuelle Konfiguration an Vergrößern

Steht vom Hersteller ein neues Firmware-Upgrade bereit, können Benutzer es ebenfalls über die Weboberfläche des Shields flashen.

Firmware-Upgrade über Webpanel
Firmware-Upgrade über Webpanel Vergrößern

Auf der Einstellungsseite lassen sich Systemdaten konfigurieren wie Name des Shields, Login-Information oder Netzwerkeinstellungen. Rechts oben auf dem Bild sehen Sie auch einen Link auf die erweiterte Konfigurationsschnittstelle LuCI:

Im Webserver lassen sich Systemparameter wie Name, Login oder Netzwerkeinstellungen verändern
Im Webserver lassen sich Systemparameter wie Name, Login oder Netzwerkeinstellungen verändern Vergrößern

Apropos LuCI. Für umfangreichere Konfigurationen gibt es das erweiterte Konfigurationspanel namens LuCI (Lua Configuration Interface), mit dem Maker Zugriff auf sehr viele Systemparameter haben:

luci bietet erweiterte Konfigurationsmöglichkeiten
LuCI bietet erweiterte Konfigurationsmöglichkeiten Vergrößern

Zugriff über ein Linux-Terminal

Natürlich können Sie auch auf eine Linux-Konsole zugreifen. Der Autor hat sein System über die Konfiguration in MichaelsYunShield umbenannt. Deshalb ist der Zugriff auf eine Linux-Konsole möglich über:

ssh [email protected]

Nach Eingabe des Passworts und einer zu ignorierenden Warnung, dass die Authentizität des Systems noch nicht verifiziert sei, erscheint die Shell-Konsole:

Zugriff über Linux-Konsole
Zugriff über Linux-Konsole Vergrößern

Auf dem Yún beziehungsweise auf dem Yún Shield läuft eine Embedded-Linux-Distribution namens OpenWrt, die unter anderem auch für Wireless Router (daher auch der Name OpenWrt), Smartphones oder Pocketcomputer zum Einsatz kommt. Laut Wikipedia bietet “OpenWrt ein voll beschreibbares Dateisystem und beinhaltet den Paketmanager opkg. Das ist insbesondere für den Einsatz in CPE- und WLAN-Routern einzigartig. Die Paket-Quellen beinhalteten im Oktober 2013 mehr als 3700 Software-Pakete, die es dem Anwender erlauben, den Router sehr weitläufig zu konfigurieren und die ursprünglichen Funktionen der originalen Firmware um ein Vielfaches zu erweitern.”

Neue Yún-Boards (ab 2015) basieren in der Regel nicht direkt auf OpenWrt, sondern verwenden stattdessen LininoOS (Linino.org), eine auf OpenWrt basierende Distribution mit IoT-Fokus. Wer möchte, kann zusätzlich zur Installation von LininoOS auf dem Linux-Subsystem das Framework LininoIO auf der Arduino-MCU (Microcontroller-Unit) installieren. Hinweise dazu finden sich zum Beispiel hier. Dadurch steuern Entwickler den Arduino-Microcontroller auch ohne C an, beispielsweise über Node.js. Information befindet sich dazu auch in folgender Präsentation. Hat ein Arduino Yún-Board noch OpenWrt installiert, ist vor Installation von LininoIO ein Upgrade auf LininoOS notwendig.

Zugriff über die Arduino IDE

Nach erfolgreicher Installation/Konfiguration des Yún Board/Shield können Entwickler über die Arduino IDE ihres Hostsystems Sketche auf den Yún laden. Voraussetzung ist die Konfiguration des Boardmanagers in der IDE über das Sub-Menü Preferences, sofern für das verwendete Board/Shield notwendig.

Dort geben Sie zum Beispiel für das Dragino Yún Shield an entsprechender Stelle (Additional Boards Manager URL) ein:

http://www.dragino.com/downloads/downloads/YunShield
/package_dragino_yun_test_index.json

Eingabe der erforderlichen Boardsmanagers URL für das Dragino Yun Shield
Eingabe der erforderlichen Boardsmanagers URL für das Dragino Yún Shield Vergrößern

Anschließend tauchen im Menü Tools zusätzliche Optionen für die Einstellung von Board und Port auf. Bei meinem Mac lautet der Netzwerkport zum Beispiel MichaelsYunShield at 192.168.178.74 (Arduino Yún) und das Board Arduino Mega 2560 – Dragino Yun:

Hier lassen sich im Tools-Menü Yun Board/Shield und der Netzwerkport einstellen
Hier lassen sich im Tools-Menü Yún Board/Shield und der Netzwerkport einstellen Vergrößern

Zum Test übersetzen Sie das obligatorische Blink-Programm aus File | Examples | 01.Basics und laden es über das Netzwerk auf das Board. Initial werden Sie in einer Dialogbox aufgefordert, das Passwort Ihres Yún-Systems einzugeben, ohne das die IDE keine Sketche auf das Board laden kann.

Kompilieren und Upload des Blink-Sketches auf Yun
Kompilieren und Upload des Blink-Sketches auf Yún Vergrößern

Platz schaffen

Mit dem vorhandenen Speicher auf dem Yún kommen Entwickler in der Praxis nicht sehr weit. Noch dazu raten die Väter des Boards davon ab, ausgiebig den Flash-Speicher des Linux-Subsystems zu nutzen, weil dieser nach zu vielen Schreibzyklen immer mehr Fehler erzeugt. Zum Glück hat das Arduino Yún Board/Shield einen Micro-SD-Kartenslot. Den können Maker nutzen, um den Speicher des Linux-Subsystems auf ein vernünftiges Maß zu erhöhen.

Zu diesem Zweck benötigen sie eine frische Micro-SD-Karte. Um diese für ihr Board nutzbar zu machen, gibt es zwei Möglichkeiten.

Option A: Sie verwenden den Sketch YunShieldExpander aus dem zugehörigen Tutorial. Bei Yun-Shields wie dem von Dragino müssen Sie den Sketch allerdings noch modifizieren wie hier beschrieben.

Option B: Sie geben in der Linux-Konsole ein:

wget -O simplesd.sh https://www.dropbox.com/s/jl4oytptxrb6q5u/simplesd.sh?dl=0 --no-check-certificate

worauf das Herunterladen eines Shell-Skripts erfolgt, das sie anschließend ausführen:

/bin/ash simplesd.sh

Das von sonny yu über Dropbox-Link bereitgestellte Skript erledigt alles, was notwendig ist:

opkg update
opkg install e2fsprogs fdisk
if fdisk -l |grep /dev/sda > /dev/null; then
echo "Start"
else
echo "/dev/sda not found!"
exit 0
fi
dd if=/dev/zero of=/dev/sda bs=4096 count=10
(echo n; echo p; echo 1; echo; echo; echo w) | fdisk /dev/sda
umount -f /mnt/sda1
mkfs.ext4 /dev/sda1
mkdir -p /mnt/sda1
mount /dev/sda1 /mnt/sda1
mkdir -p /tmp/cproot
mount --bind / /tmp/cproot
tar -C /tmp/cproot -cvf - . | tar -C /mnt/sda1 -xf -
umount /tmp/cproot
uci add fstab mount
uci set [email protected][0].target=/
uci set [email protected][0].device=/dev/sda1
uci set [email protected][0].fstype=ext4
uci set [email protected][0].enabled=1
uci set [email protected][0].enabled_fsck=0
uci set [email protected][0].options=rw,sync,noatime,nodiratime
uci commit
reboot

Brückenbau

Es war bereits von der Bridge die Rede. Zwischen OpenWrt- bzw. Linino- und Arduino-Subsystem gibt es eine serielle Verbindung mit je einem Transferausgang und einem Leseeingang. Zudem existiert eine Softwarebibliothek (Bridge Library), um auf diese Brücke programmatisch zuzugreifen. Sinn der Brücke ist die Integration von Linux- und Arduino-Welt.

Von der Arduino-Seite lässt sich über die Bibliothek von einem Sketch auf OpenWrt/Linino zugreifen. Umgekehrt können Python-Programme über die Bridge dank einer Linux-seitigen Bibliothek mit der Arduino MCU kommunizieren – Python 2.7 liegt auf OpenWrt/Linino bereits installiert vor.

Zuerst steht die Bridge Library im Vordergrund. Neben Funktionen zum Starten der Bridge-Verbindung oder zum Datentransfer bietet die Bibliothek folgende Klassen (siehe auch die Beschreibung auf arduino.cc):

  • Process ermöglicht unter anderem den Zugriff auf Linux-Shell-Kommandos und Prozesse.
  • Console dient (vergleiche Serial) zur seriellen Kommunikation mit der Arduino IDE (serieller Monitor).
  • FileIO dient zum Dateizugriff, etwa auf der MicroSD-Karte oder über USB angeschlossenem Speicher.
  • HttpClient kreiert einen HTTP-Client auf der Linux-Seite und verhält sich wie ein Adapter für CURL-Kommandos.
  • Mailbox implementiert zustandlose, asynchrone Kommunikation zwischen Linux und Arduino.
  • BridgeClient fungiert als Schnittstelle, mit der ein Sketch als HTTP Client agieren kann.
  • BridgeServer dient zum Bereitstellen eines Arduino-basierten HTTP-Servers.

Die Python-Bibliothek YunBridge ist leider nicht sehr gut dokumentiert. Am besten ist ein Blick auf die Python-Dateien der aktuellen Version, die über GitHub verfügbar ist.

Beispiel 1: Steuern einer LED über Python

Im ersten Beispiel soll der Arduino auf Nachrichten von einem Python-Skript warten. Dieses überträgt Buchstaben ‘0’ oder ‘1’. Bei ‘0’ schaltet der Sketch die LED an Pin 13 ein, bei ‘1’ schaltet er sie aus. Entsprechend einfach ist der Sketch strukturiert:

#include <Bridge.h>

// Empfang der Nachrichten aus Linux
// über folgende Variable:

char valuePin13[2] = {0};

void setup() {


// Pin 13 wird als Ausgang verwendet
pinMode(13, OUTPUT);
// und ist anfangs ausgeschaltet:
digitalWrite(13, LOW);


// Hier startet die Bridge:
Bridge.begin();
}

void loop() {
// Empfangen eines Wertes und Einlesen in valuePin13:
Bridge.get("Pin13", valuePin13, 2);
// Der empfangene Buchstabe wird in eine Zahl konvertiert:
int result = atoi(valuePin13);
// und deren Wert an Pin 13 angelegt (LED geht an oder aus):
digitalWrite(13, result);

// Etwas warten
delay(50);
}

Jetzt lässt sich der Sketch auf das Arduino-Subsystem übertragen.

Auf der OpenWrt/Linino-Konsole gibt der Entwickler nun seinem Lieblingseditor das Python-Script ein. Ich habe es pin13control.py getauft.

#!/usr/bin/python 

# Bibliothek YunBridge importieren:
import sys
sys.path.insert(0, '/usr/lib/python2.7/bridge')

from time import sleep

# Client fuer Zugriff auf Bridga anlegen:
from bridgeclient import BridgeClient as bridgeClient
value = bridgeClient()

# Solange loop == 1 laeuft die while-Schleife:
loop = 1
# Antwort des Benutzers wird hier gespeichert:
answer = 0

# while-Schleife zur Abfrage ob LED ein- oder ausgeschaltet
# werden soll, oder ob abgebrochen werden soll (Eingabe < 0):

while(loop):
print("number > 0 => LED on Pin 13 is turned onn");
print("number = 0 => LED on Pin 13 is turned offn");
print("number < 0 => end of loop n");

x = int(input("Enter a number: "));
if x < 0:
loop = 0
elif x > 0:
value.put('Pin13','1')
else:
value.put('Pin13','0')

print("Done!n")

Nun müssen die Dateiattribute von pin13control.py noch um Ausführbarkeit ergänzt werden:

chmod a + x pin13control.py

Dann lässt sich das Skript in der Shell starten:

./pin13control.py

Anschließend ist ähnliches zu sehen wie das folgende:

[email protected]:~# ./pin13control.py
number > 0 => LED on Pin 13 is turned on

number = 0 => LED on Pin 13 is turned off

number < 0 => end of loop

Enter a number: 4
number > 0 => LED on Pin 13 is turned on

number = 0 => LED on Pin 13 is turned off

number < 0 => end of loop

Enter a number: 0
number > 0 => LED on Pin 13 is turned on

number = 0 => LED on Pin 13 is turned off

number < 0 => end of loop

Enter a number: 5
number > 0 => LED on Pin 13 is turned on

number = 0 => LED on Pin 13 is turned off

number < 0 => end of loop

Enter a number: -12
Done!

[email protected]:~#

Beispiel 2: Lesen des Analogeingangs A0

Im zweiten Beispiel drehen wir den Spieß um. Ein Arduino-Sketch übernimmt die aktive Rolle und sendet immer wieder Daten an Python. Konkret meldet er jede Sekunde den augenblicklichen Wert von Analog-Port A0:

#include <Bridge.h>

void setup() {
// Hier startet die Bridge:
Bridge.begin();
}

void loop() {
// Lesen des Wertes von A0:
int value = analogRead(A0);

// und als Wert A0 an Python senden
Bridge.put("A0", String(value));

delay(1000);
}

Das zugehörige Python-Skript läuft auf der OpenWrt/Linino-Shell, empfängt die eingehenden Messwerte vom Arduino-Sketch, und gibt sie aus.

#!/usr/bin/python

# YunBridge importieren:
import sys
sys.path.insert(0, '/usr/lib/python2.7/bridge')

from time import sleep

# Ueber value erfolgt der Zugriff auf die Kommunikation:
from bridgeclient import BridgeClient as bridgeclient
value = bridgeclient()

# Endlosschleife:
while(1):
# Wert fuer A0 holen:
msg = value.get("A0")
# und ausgeben:
print msg
# und nach einer Pause weiter
sleep(0.1)

Beispiel 3: Temperatur abfragen

Das zweite Beispiel lässt sich noch etwas ausbauen. Bisher liefert der Arduino-Sketch nur Zufallswerte. Diesmal soll ein Temperatursensor des Typs TMP36 über Analogport A0 echte Temperaturwerte liefern, genauer gesagt, die gelesenen Digitalwerte nach der Analog-Digital-Konvertierung. Die eigentliche Temperaturberechnung daraus soll der Python-Code vornehmen.

Die zugehörige Schaltung ist geradezu trivial:

Yun mit TMP36 (Anschluss über A0)
Yún mit TMP36 (Anschluss über A0) Vergrößern

Der Arduino-Sketch misst die Temperatur und sendet sie permanent über die Yún Bridge. Es ist exakt der gleiche Sketch wie im vorangegangenen Beispiel.

Das Python-Skript ist etwas komplexer. Dort ist ein Bereich von Temperaturen über die Vereinbarungen von mintemp und maxtemp festgelegt.

In jeder Schleifeniteration liest das Python-Skript die vom Arduino-Subsystem empfangenen Messwerte über die Bridge ein:

analogValue = int(value.get("A0"))

Dieser Wert wird genutzt, um die Temperatur zu berechnen. Wie der TMP36 funktioniert, war bereits Gegenstand einer früheren Folge. Liegt die Temperatur im zulässigen Bereich, passiert bis auf eine Diagnoseausgabe nichts weiter. Liegt sie darüber oder darunter, versendet das Skript über Google Mail eine Meldung an den in recipient festgelegten Empfänger.

Um die Mail-Funktionalität über SSL zu nutzen, ist vorher noch eine Paketinstallation vonnöten:

opkg update
opkg find python-openssl
opkg install python-openssl

Die rot markierten Parameter für die Mail-Einstellungen im folgenden Skript sollten Sie mit Ihren eigenen Werten überschreiben.

#!/usr/bin/python 
import time
import sys
import smtplib
sys.path.insert(0, '/usr/lib/python2.7/bridge/')

from bridgeclient import BridgeClient as bridgeclient

maxtemp = 25
mintemp = 20
delta = 10
recipient = '[email protected]'
login = '[email protected]'
password = 'xxxxxxxx'
subject = 'Temperature Alert'
messageV = 'Temperature measured is '
smtpServer= "smtp.gmail.com"
smtpPort = 587
NL = 'n'


mintempAsStr = "{:.2f}".format(mintemp)
maxtempAsStr = "{:.2f}".format(maxtemp)
message = 'Temperature out of range ' + mintempAsStr + ' .. '
+ maxtempAsStr

value = bridgeclient()

#sending mail
def send_email():
print("Sending Email")
mailSmtp = smtplib.SMTP(smtpServer, smtpPort)
mailSmtp.ehlo()
mailSmtp.starttls()
mailSmtp.ehlo
mailSmtp.login(login, password)
header = 'To:' + recipient + NL + 'From: ' + login
header = header + NL + 'Subject:' + subject + NL
print header
body = message + NL + NL + messageT + NL + NL
print body
mail = header + NL + body
mailSmtp.sendmail(login, recipient, mail)
mailSmtp.close()


while True:
analogValue = int(value.get("A0"))
temperature = (analogValue * 0.00488281 - 0.5) * 100.0
temperatureAsStr = "{:.2f}".format(temperature)

if (temperature > maxtemp) or (temperature < mintemp):
print "sending temperature alert"
messageT = messageV + ' ' + temperatureAsStr + ' C'
send_email()
else:
print "no message sent"
print "temperature measured was " + temperatureAsStr

time.sleep(delta)

Die Diagnose-Ausgabe in der Shell könnte zum Beispiel wie folgt aussehen. Einen Temperatursprung können Sie erreichen, indem Sie den Temperatursensor mit den Fingern wärmen.

[email protected]:~# ./mailtemp.py
sending temperature alert
Sending Email
To:[email protected]
From: [email protected]
Subject:Temperature Alert

Temperature out of range 20.00 .. 25.00

Temperature measured is 19.34 C


sending temperature alert
Sending Email
To:[email protected]
From: [email protected]
Subject:Temperature Alert

Temperature out of range 20.00 .. 25.00

Temperature measured is 25.20 C


no message sent
temperature measured was 22.27
Beispiel 4: Arbeiten mit Shell Commands

Im vierten und letzten Beispiel kommt die Schaltung von Beispiel 3 erneut zum Einsatz. Anstelle eines ständig laufenden Python-Skripts in der Linux-Shell des Yún steht auf der Linino/OpenWrt-Seite allerdings ein modifiziertes Python-Skript zur Verfügung, das den vom Arduino am Temperatursensor TMP36 gemessenen Analogwert als Kommandozeilenargument übergeben bekommt. Bei Nichteinhaltung der Temperaturgrenzen versendet das Python-Programm eine E-Mail. Sie sollten hier wieder Ihre eigenen Mail-Zugangsdaten eintragen. Die Unterschiede zum Python-Skript in Beispiel 3 bestehen darin, dass die endlose while-Schleife weggefallen ist, und dass das Programm den Analogwert als Kommandozeilenargument übergeben bekommt:

analogValue = int(sys.argv[1])

sodass sich insgesamt folgender Python-Code ergibt:

#!/usr/bin/python
import time
import sys
import smtplib


maxtemp = 22
mintemp = 16
delta = 10
recipient = '[email protected]'
login = '[email protected]'
password = 'xxxxxxxx'
subject = 'Temperature Alert'
messageV = 'Temperature measured is '
smtpServer= "smtp.gmail.com"
smtpPort = 587
NL = 'n'


mintempAsStr = "{:.2f}".format(mintemp)
maxtempAsStr = "{:.2f}".format(maxtemp)
message = 'Temperature out of range ' + mintempAsStr + ' .. '
+ maxtempAsStr


#function to send email
def send_email():
print("Sending Email")
mailSmtp = smtplib.SMTP(smtpServer, smtpPort)
mailSmtp.ehlo()
mailSmtp.starttls()
mailSmtp.ehlo
mailSmtp.login(login, password)
header = 'To:' + recipient + NL + 'From: ' + login
header = header + NL + 'Subject:' + subject + NL
print header
body = message + NL + NL + messageT + NL + NL
print body
mail = header + NL + body
mailSmtp.sendmail(login, recipient, mail)
mailSmtp.close()


analogValue = int(sys.argv[1])
temperature = (analogValue * 0.00488281 - 0.5) * 100.0
temperatureAsStr = "{:.2f}".format(temperature)

if (temperature > maxtemp) or (temperature < mintemp):
print "sending temperature alert"
messageT = messageV + ' ' + temperatureAsStr + ' C'
send_email()
else:
print "no message sent"
print "temperature measured was " + temperatureAsStr

Im Arduino-Sketch erfolgen analog die Messungen des Analogeingangs A0. Dieses Mal sendet der Arduino keine Analogwerte über die Bridge, sondern lässt in der Unix-Shell ein Kommando ausführen.

Unter der Linux-Shell ruft die Bridge das Python-Skript runmail.py auf. Dabei soll der gemessene Analogwert dem Skript als Kommandozeilen-Parameter dienen:

int value = analogRead(A0);
String command = String("/usr/bin/python /root/runmail.py ") + String(value);

In der Zeile

p.runShellCommand(command);

erfolgt der eigentliche Aufruf.

Anschließend wartet der Sketch bis das Python-Skript auf Linux-Seite seine Arbeit verrichtet hat:

while (p.running()); 

Nun könnten wir am Arduino noch Rückmeldungen des Python-Skripts verarbeiten. Im vorliegenden Fall ignoriert der Arduino-Sketch jedoch eventuelle Rückmeldungen:

while (p.available()) {
char c = p.read();
}

Das Arduino-Programm ist also immer noch von sehr einfacher Natur:

#include <Bridge.h>

// Zeit zwischen Messungen in Sekunden
const int waitTime = 10;

void setup() {
// Hier startet die Bridge:
Bridge.begin();
}

void loop() {
// Process-Objekt anlegen:
Process p;
// Lesen des Wertes von A0:
int value = analogRead(A0);
String command = String("/usr/bin/python /root/runmail.py ") + String(value);
p.runShellCommand(command);
while (p.running());
// Rückgaben ignorieren!
while (p.available()) {
char c = p.read();
}
// Pause zwischen den Messungen
delay(waitTime * 1000);
}

Nutzen der REST API

Sie können auch mittels Web Browser einzelne Pins des Arduino Yún abfragen oder überschreiben. Je nachdem, ob in der Konfiguration ein REST API Zugriff nur über Passwort eingestellt ist oder nicht, erscheint vor dem ersten Zugriff ein Dialogfenster zur Eingabe der Zugangsdaten.

Zugriffe über Browser sehen folgendermaßen aus:

  • http://myArduinoYun.local/arduino/digital/13 : entspricht digitalRead(13);
  • http://myArduinoYun.local/arduino/digital/13/1 : entspricht digitalWrite(13,1);
  • http://myArduinoYun.local/arduino/analog/9/123 : entspricht analogWrite(9,123);
  • http://myArduinoYun.local/arduino/analog/2 : entspricht analogRead(2);
  • http://myArduinoYun.local/arduino/mode/13/input : entspricht pinMode(13, INPUT);
  • http://myArduinoYun.local/arduino/mode/13/output : entspricht pinMode(13, OUTPUT);

Der Autor hat sein Arduino Yun Shield in MichaelsYunShield umgetauft, weshalb er die Aufrufe über Aufrufe wie http://MichaelsYunShield/arduino/digital/13/1 tätigt.

Den frei verfügbaren Sketch finden Sie inklusiver zahlreicher Erläuterungen unter folgender Webseite. Dass hier von REST API die Rede ist, sollten Entwickler mit Vorsicht genießen. Die obigen URLs entsprechen de facto mangels JSON keinen REST-Aufrufen.

Achtung: Die in der Webseite erwähnten Klassen YunClient und YunServer sind abgekündigt (engl. deprecated). Daher nutzt der untere Sketch anstatt dieser die neuen Klassen BridgeClient und BridgeServer.

Der Code ist rein aus Gründen des Komforts hier unverändert abgedruckt:

/*
Arduino Yún Bridge example

This example for the YunShield/Yún shows how
to use the Bridge library to access the digital and
analog pins on the board through REST calls.
It demonstrates how you can create your own API when
using REST style calls through the browser.

Possible commands created in this shetch:

"/arduino/digital/13" -> digitalRead(13)
"/arduino/digital/13/1" -> digitalWrite(13, HIGH)
"/arduino/analog/2/123" -> analogWrite(2, 123)
"/arduino/analog/2" -> analogRead(2)
"/arduino/mode/13/input" -> pinMode(13, INPUT)
"/arduino/mode/13/output" -> pinMode(13, OUTPUT)

This example code is part of the public domain

http://www.arduino.cc/en/Tutorial/Bridge

*/


#include <Bridge.h>
#include <BridgeServer.h>
#include <BridgeClient.h>

// Listen to the default port 5555, the Yún webserver
// will forward there all the HTTP requests you send

BridgeServer server;

void setup() {
// Bridge startup
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
Bridge.begin();
digitalWrite(13, HIGH);

// Listen for incoming connection only from localhost
// (no one from the external network could connect)

server.listenOnLocalhost();
server.begin();
}

void loop() {
// Get clients coming from server
BridgeClient client = server.accept();

// There is a new client?
if (client) {
// Process request
process(client);

// Close connection and free resources.
client.stop();
}

delay(50); // Poll every 50ms
}

void process(BridgeClient client) {
// read the command
String command = client.readStringUntil('/');

// is "digital" command?
if (command == "digital") {
digitalCommand(client);
}

// is "analog" command?

if (command == "analog") {
analogCommand(client);
}

// is "mode" command?
if (command == "mode") {
modeCommand(client);
}
}

void digitalCommand(BridgeClient client) {
int pin, value;

// Read pin number
pin = client.parseInt();

// If the next character is a '/' it means we have an URL
// with a value like: "/digital/13/1"

if (client.read() == '/') {
value = client.parseInt();
digitalWrite(pin, value);
} else {
value = digitalRead(pin);
}

// Send feedback to client
client.print(F("Pin D"));
client.print(pin);
client.print(F(" set to "));
client.println(value);

// Update datastore key with the current pin value
String key = "D";
key += pin;
Bridge.put(key, String(value));
}

void analogCommand(BridgeClient client) {
int pin, value;

// Read pin number
pin = client.parseInt();

// If the next character is a '/' it means we have an URL
// with a value like: "/analog/5/120"

if (client.read() == '/') {
// Read value and execute command
value = client.parseInt();
analogWrite(pin, value);

// Send feedback to client
client.print(F("Pin D"));
client.print(pin);
client.print(F(" set to analog "));
client.println(value);

// Update datastore key with the current pin value
String key = "D";
key += pin;
Bridge.put(key, String(value));
} else {
// Read analog pin
value = analogRead(pin);

// Send feedback to client
client.print(F("Pin A"));
client.print(pin);
client.print(F(" reads analog "));
client.println(value);

// Update datastore key with the current pin value

String key = "A";
key += pin;
Bridge.put(key, String(value));
}
}

void modeCommand(BridgeClient client) {
int pin;

// Read pin number
pin = client.parseInt();

// If the next character is not a '/' we have a malformed URL
if (client.read() != '/') {
client.println(F("error"));
return;
}

String mode = client.readStringUntil('r');

if (mode == "input") {
pinMode(pin, INPUT);
// Send feedback to client
client.print(F("Pin D"));
client.print(pin);
client.print(F(" configured as INPUT!"));
return;
}

if (mode == "output") {
pinMode(pin, OUTPUT);
// Send feedback to client
client.print(F("Pin D"));
client.print(pin);
client.print(F(" configured as OUTPUT!"));
return;
}

client.print(F("error: invalid mode "));
client.print(mode);
}
cURL statt Webbrowser

Statt beim Nutzen der REST API über den Webbrowser zu gehen, gibt es ebenfalls die Option, cURL (Client for URLs) zu verwenden, das primär zum Test von Web-Schnittstellen dient.

Um den augenblicklichen Wert von Digitalport 13 abzufragen, ist beispielsweise folgender Aufruf notwendig:

curl http://root:passwort@myArduinoYun/arduino/digital/13/

Auf meinem System lautet die Rückmeldung:

Pin D13 set to 0

Zum Einschalten der LED an Digitalausgang 13 genügt der Aufruf von:

curl http://root:passwort@myArduinoYun/arduino/digital/13/1

mit der Antwort:

Pin D13 set to 1

Für die Abfrage des analogen Ports A0 lautet das cURL-Kommando

curl http://root:passwort@myArduinoYun/arduino/analog/0

worauf folgende Antwort zurückkommt:

Pin A0 reads analog 147

Um cURL auf Ihrem System nutzen zu können, sofern nicht schon vorhanden, besuchen Sie dessen Download-Seiten.

Zusammenfassung

Wie immer kann eine Blogfolge nur die Spitze des Eisberges betrachten. Es gibt wesentlich mehr Möglichkeiten, als der Beitrag illustrieren konnte. Zum Beispiel ist es möglich, den Arduino-Sketch über die Bridge als HTTP-Client oder HTTP-Server agieren zu lassen. Ebenso lassen sich etwa Sensordaten über eine Micro-SD-Karte protokollieren. Der Dienst Temboo ermöglicht in Kombination mit dem Yún weitere interessante Projekte (siehe Link).

Arduino Yún Boards und speziell die Shields lohnen sich insbesondere dann, wenn Maker auf Basis des Arduino-Ökosystems komplexere Projekte durchführen möchten, die von den erweiterten Möglichkeiten und der Performanz eines Embedded-Linux-Systems profitieren. Exemplarisch sei hier die Integration ins Web genannt. Da ein Yún-Shield meistens sogar unter den Preisen entsprechender WiFi-Shields liegt, bietet sich hier preislich eine echte Alternative.

Auch in Zukunft komme ich sicher immer wieder auf den Arduino Yún zu sprechen. Bis dahin sollten Ihnen seine kreativen Möglichkeiten einige Freude bereiten.

Read more on: Source

Comments are disabled