Archiv der Kategorie: Arduino

Arduino WiFi für unter 3 Euro – der ESP8266

IMG_20150116_090344

In den letzten Monaten ist ein regelrechter Hype ausgebrochen um den ESP8266, ein Chip aus chinesischer Entwicklung, der auf einer winzigen Fläche sowohl Access Point als auch WiFi Client sein kann. Inzwischen exisitieren verschiedene Breakout Boards, die zunächst eine UART-WiFi Schnittstelle bereitstellen und auf eBay für unter 3 Euro gehandelt werden. Da der Chip einen 32bit Prozessor enthält kann er aber auch mit eigener Firmware bestückt werden. Ich möchte mich hier nicht näher mit Details beschäftigen, da es bereits viele Webseiten zu diesem Thema gibt. Eine kurze und knappe Zusammenfassung auf deutsch mit Verlinkung zu weiteren Seiten hat das FabLab Nürnberg erstellt.

Inzwischen konnte ich einige Erfahrungen mit diesem Modul machen und solange man kein Highspeed WiFi braucht ist das Modul eine gute Wahl und macht für kleines Geld IoT möglich. Die ersten Versuche mit diesem Modul habe ich in Verbindung mit einem Arduino MEGA gemacht. Der MEGA hat mehrere in Hardware implementierte serielle Schnittstellen, so kann man sowohl die Verbindung zum Computer als auch die Verbindung zum ESP8266 mit 115200 Baud laufen lassen. In den neueren Firmwares des ESP ist die Baudrate aber auch einstellbar, so dass ein Betrieb an einer SoftSerial Schnittstelle bei z.B. 9600 Baud, damit an einem UNO, auch möglich ist.  Die Verbindung des ESP an den MEGA muss über Pegelwandler 5V->3.3V erfolgen, die Schnittstelle ist hier nicht tolerant. Ich habe die Verbindung von TX (MEGA) zu RX (ESP) über einen Spannungsteile aus 1k und 2.2k herunter geteilt. Der ESP braucht einen eigenen 3.3V Spannungswandler, der 3.3V Ausgang des Arduino liefert zu wenig Strom für den ESP (max 200mA).

Für erste Experimente, bei denen die AT Befehle „per Hand“ eingegeben werden, eignet sich das folgende kurze Programm.

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  Serial.println("Program started");
}

void loop() {
  if(Serial1.available()) {   
    char ser = Serial1.read();
    /*if (ser==10) {         // kann genutzt werden, um ein Gefühl für die Antwortzeiten zu bekommen
      Serial.print("  ");
      Serial.print(millis());
    }*/
    Serial.print(ser);
  }
  if(Serial.available()) {   
    char ser = Serial.read();
    Serial1.print(ser);
  }
}

Die meisten Einstellungen des Chip bleiben über ein Power on Reset bestehen. Es ist also nicht notwendig, im Programm die Einstellungen jedes mal neu zu setzen. Ich habe mir zu diesem Zweck ein Programm erstellt mit den wichtigsten Einstellungen (Access Point, SSID, PASS, Client usw.). Mit diesem Programm mache ich die Grundkonfiguration des Chip.

// ESP_Minimal.ino - sketch to quickly view and change some of ESP8266 parameters
// most of the ESP parameters are stored in eeprom, so also outlive the power on reset
// special thanks to http://rayshobby.net/?p=9734
// sketch is written for ArduinoMega, ESP connected with voltage devider to Serial1
// This code is in the public domain.

#define SET // for just viewing parameters, set this as comment

#define BUFFER_SIZE 512
#define esp Serial1
#define dbg Serial //For debugging purposes

char buffer[BUFFER_SIZE];
char OKrn[] = "OK\r\n";
int mode;

boolean wait_for_esp_response(int timeout, char* term=OKrn) {
 unsigned long t=millis();
 bool found=false;
 int i=0;
 int len=strlen(term);
 // wait for at most timeout milliseconds
 // or if OK\r\n is found
 while(millis()<t+timeout) {
 if(esp.available()) {
 buffer[i++]=esp.read();
 if(i>=len) {
 if(strncmp(buffer+i-len, term, len)==0) {
 found=true;
 break;
 }
 }
 }
 }
 buffer[i]=0;
 dbg.print(buffer);
 return found;
}

void setup() {
 esp.begin(115200); //esp baud rate
 dbg.begin(115200); //debugger baud rate
 dbg.println("start of program ...");
 esp.println("AT"); // check for existence of ESP8266
 if (!wait_for_esp_response(1000)) {
 dbg.println("no ESP found");
 while(true); // hang forever
 }
 // some important checks of operation modes
 esp.println("AT+CWMODE?"); // check mode 1=Client, 2=AP, 3=both
 wait_for_esp_response(1000);
 char *result = strstr(buffer, "+CWMODE:");
 if (result!=0) {
 mode=atoi(result+8);
 if (mode!=1) {
 esp.println("AT+CWSAP?"); // actual AP configuration
 }
 if (mode!=3) {
 esp.println("AT+CWJAP?"); // actual connected WiFi
 wait_for_esp_response(1000);
 }
 }

 esp.println("AT+CIPMUX?"); // check connection mode 0=single, 1=multiple
 wait_for_esp_response(1000);
 esp.println("AT+CIPMODE?"); // check data mode 0=normal, 1=transparent
 wait_for_esp_response(1000);
 esp.println("AT+CIFSR"); // actual IP adress
 wait_for_esp_response(1000);

#ifdef SET
 esp.println("AT+CWMODE=3"); // set mode 1=Client, 2=AP, 3=both
 wait_for_esp_response(1000);
 // set AP or Client
 esp.println("AT+CWMODE?"); // check mode 1=Client, 2=AP, 3=both
 wait_for_esp_response(1000);
 result = strstr(buffer, "+CWMODE:");
 if (result!=0) {
 if (mode!=1) { // AP settings
 esp.println("AT+CWSAP=\"ESP_9F2556\",\"blablabla\",1,3"); // set AP: SSID, PASS, channel, encryption
 wait_for_esp_response(1000); // 0=open, 1=WEP, 2=WPA_PSK, 3=WPA2_PSK, 4=WPA_WPA2_PSK
 }
 if (mode!=2) { // Client settings
 esp.println("AT+CWJAP=\"yourSSID\",\"passphrase\""); // connect client to AP
 wait_for_esp_response(5000); // was really that long!
 }
 }

#endif

 esp.println("AT+RST"); // RESET, necessary for some changes of settings
 wait_for_esp_response(3000, "ready");
}

void loop() {

}

Die zu ändernden Parameter werden direkt im Code verändert. Wenn die erste Zeile #define SET auskommentiert wird, werden die wichtigsten Parameter nur angezeigt.

Werbeanzeigen

Arduino goes Wireless

Die Experimente zu meinem Tutorial  „Speicherung von Arduino Messdaten auf Webserver und deren Darstellung“ setzten alle auf einen Arduino mit Ethernet Shield zur Verbindung mit dem Internet auf. Nun gibt es Situationen, wo kein Ethernet Anschluss in Reichweite ist, trotzdem aber die Verbindung ins Internet benötigt gewollt ist. Oder es ist Mobilität gefordert, während Daten übertragen werden. Das Arduino Wifi Shield wäre eine Lösung, ist aber mit fast 70€ eine sehr kostspielige und zusätzlich muss das Programm daraufhin angepasst werden. Eine wesentlich kostengünstigere und ohne Anpassung des Programms einsetzbare Lösung ist ein Wireless Client. Ich habe mich für den TP-Link TL-WR702N entschieden, der schon inklusive Versand für weniger als 20€ zu bekommen ist.

IMG_20150114_181434

Der TL-WR702N ist im Auslieferungszustand ein Access Point, für unsere Anwendung muss er aber als Client oder als Bridge konfiguriert werden. Der TL-WR702N stellt als Client über WLAN die Verbindung zum Access Point her, der Arduino mit Ethernet Shield wird mit dem TL-WR702N über die Ethernet Schnittstelle verbunden und verhält sich genauso, wie bei direkter Verbindung nur über Ethernet.

Die Konfiguration als Client ist im Handbuch ausreichend beschrieben, deshalb möchte ich hier nicht näher darauf eingehen. Einen Sonderfall möchte ich an dieser Stelle näher beschreiben, nämlich, wenn ich keinen Rechner zur Verfügung habe, den TL-WR702N zu konfigurieren. Eine Konfiguration über Wireless, z.B. mit einem Smartphone oder Tablet ist im Handbuch nicht beschrieben.

Nachfolgend gehe ich davon aus, dass der TL-WR702N im Auslieferungszustand vorliegt. Dieser Zustand kann jederzeit hergestellt werden, indem der Reset Taster mit einem spitzen Gegenstand z.B. einer aufgebogenen Büroklammer, für ca. 7 Sekunden gedrückt wird, bis die Betriebs LED mehrmals kurz blinkt. Die nachfolgenden Schritte habe ich mit meinem Nexus 7 durchgespielt, mit anderen Geräten kann das leicht variieren.

Zunächst verbinde ich mich mit dem Tablet auf den Access Point des TL-WR702N. Die SSID, nach der ich suche, steht auf dem Typenschild des TL-WR702N, ebenso die zugehörige Passphrase.

Screenshot_2015-01-14-16-45-17_bea

Wenn ich die Verbindung hergestellt habe, wird mein Tablet eine IP aus dem 192.168.0.x Netz erhalten haben. Im Browser des Tablet gebe ich 192.168.0.254 ein, die IP des TL-WR702N zur Konfiguration. In der Abfragemaske wird für User: admin und Passwort: admin eingegeben. Wir kommen auf die Konfiguration des Routers und Erstellen eine Konfiguration für eine Bridge.

Screenshot_2015-01-14-16-59-39

Der Vorteil der Bridge Konfiguration ist, dass ich später noch über WLAN auf die Konfigurationsschnittstelle komme, um Änderungen zu machen. Das ist im Client Modus nur über Ethernet möglich. Wichtig ist jetzt, dass über Quick Setup gegangen wird, sonst verliert man nach Reboot die Konfigurationsseite. Also Quick Setup, Next, Bridge, Next.

Screenshot_2015-01-14-17-08-36

Unter Survey sehe ich die zur Verfügung stehenden WLANs und kann den gewünschten Access Point direkt mit connect auswählen. Nach Eingabe des Password für dieses WLAN gehe ich weiter mit Next. Wenn die Meldung erscheint „Your AP channel is not the same as the Bridged AP’s channel, do you want to change your channel to the Bridged AP’s channel?“ kann ich das mit OK bestätigen. Im nächsten Fenster wird kann die bestehende Verschlüsselung bestätigt werden oder eine neue Passphrase vergeben werden. Mit Next kommt man auf das letzte Fenster zum Reboot des Routers.

Screenshot_2015-01-14-17-14-33

Beim Reboot verliere ich die Verbindung zur Konfiguration des Routers. Mein Tablet verliert möglicherweise auch die Anbindung zu Access Point oder verbindet sich zu einem anderen bekannten Access Point. Eigentlich ist jetzt alles fein und ich kann mein Ethernet Shield mit dem Router verbinden und loslegen. Wenn ich die Konfiguration mit dem Tablet bearbeiten will, muss ich die IP des Routers herausfinden. Wenn ich nicht die Möglichkeit habe, die IP auf meinem Router nachzusehen, kann ich folgenden Trick anwenden. Die Android App Ping-Tools hilft mir dabei. Ich stelle über das Menü links oben die Funktion UPnP scanner ein und schon sehe ich meinen TP-Link mit seiner IP-Adresse.

Screenshot_2015-01-14-17-22-38

Über diese IP in der Browserzeile komme ich jetzt wieder auf die Konfigurationsschnittstelle, falls ich noch etwas ändern möchte. Sinnvoll wäre z.B. die Änderung des Standard Passworts für den Admin Zugang.

Der Stromverbrauch des TL-WR702N liegt übrigens nur bei ca, 150mA. Bei einer mobilen Anwendung kann der Router also ohne weiteres aus der 5V Schnittstelle des Arduino mit versorgt werden oder Arduino und der TL-WR702N werden über eine Powerbank mit USB Schnittstelle versorgt.

Als nächstes steht jetzt ein Test mit dem TP-Link TL-MR3020 an, der für unter 30€ mit gleichem Verfahren einen Arduino ins 3G/4G Mobilfunknetz und damit ins Internet bringt. Zusätzlich ist nur ein USB Stick mit Mobilfunkkarte notwendig.

 

 

Tutorial: Speicherung von Arduino Messdaten auf Webserver und deren Darstellung – Addendum

In diesem Post fasse ich einige Informationen zusammen, die ich noch loswerden wollte

Addendum1 – Config-file für MySQL Datenbank

Wenn man mit verschiedenen Abfragen einer Datenbank arbeitet und immer wieder die Zugangsdaten eingeben muss, ist das auf Dauer ziemlich nervig. Übersichtlicher ist es dann auch die Zugangsdaten separat in einen File, hier mit dem Namen config.php zuschreiben, der dann in die eigentliche Abfrage included wird.


<?php
$mysql_host = "<hier Name des Server/Host eintragen>";
$mysql_db = "<hier Datenbanknamen eintragen>";
$mysql_user = "<hier MySQL User eintragen>";
$mysql_pw = "<hier MySQL Passwort eintragen>";
$connection = mysql_connect($mysql_host, $mysql_user, $mysql_pw) or die("Verbindung zur Datenbank fehlgeschlagen.");
mysql_select_db($mysql_db, $connection) or die("Datenbank konnte nicht ausgewaehlt werden.");
?>

Die Abfrage sieht dann so aus, hier das Beipiel aus Teil 4 zur Abfrage der letzten 20 Datensätze, Zusätzlich habe ich hier die Tabelle in eine Stringvariable gesetzt. Damit wird der File leichter anpassbar für andere Tabellen.


<?php
require ($_SERVER['DOCUMENT_ROOT']."/config.php");
$mysql_table = "analog_data";
$abfrage = "SELECT datum, analog0, analog1 FROM ".$mysql_table." ORDER BY datum DESC LIMIT 20";
$ergebnis = mysql_query($abfrage);
while($row = mysql_fetch_array($ergebnis))
{
echo $row[datum].",".$row[analog0].",".$row[analog1]."<br>";
}
?>

Tutorial: Speicherung von Arduino Messdaten auf Webserver und deren Darstellung – Teil 5

Teil 5 – CSV und MySQL Daten grafisch präsentieren

Bei der Recherche, wie MySQL Daten einfach und dennoch wirkungsvoll grafisch zu präsentieren sind, habe ich mir viele Möglichkeiten angesehen. Letztendlich habe ich mich dann für dygraphs entschieden, weil diese JavaScript Library viele Möglichkeiten bietet und die Dokumentation und das Tutorial gut verständlich sind.

Um die Library einzusetzen muss zunächst der File dygraph-combined.js von der dygraphs Download-Seite geladen werden und im Basisverzeichnis des Webspaces abgelegt werden. Um die Funktionsweise der Library kennenzulernen, möchte ich  zunächst zeigen, wie die Daten aus dem csv-File aus dem 3. Teil des Tutorials dargestellt werden können. Dazu erstellen wir auf dem Webspace eine html-Seite, die im Wesentlichen dem Beispiel auf den Dygraphs Seite für csv-Dateien entspricht. Der Name dieser Datei könnte z.B. graphcsv.html sein.

<html>
<head>
<script type="text/javascript"
src="dygraph-combined.js"></script>
</head>
<body>
<div id="graphdiv2"
style="width:500px; height:300px;"></div>
<script type="text/javascript">
g2 = new Dygraph(
document.getElementById("graphdiv2"),
"test.csv", // path to CSV file
{} // Options
);
</script>
</body>
</html>

Wer jetzt schon einige Daten in seiner csv-Datei hat, sollte nach Aufruf dieser html-Seite jetzt die typische Dygraphs Grafik sehen. Dabei fällt allerdings auf, dass Dygraphs den Unix Timestamp nicht als Datum und Zeit interpretiert. Um das zu ändern, muss entweder die Speicherung der Daten geändert werden oder dem dygraphs-Aufruf eine optionale Funktion mitgegeben werden. Die Option wird in den geschweiften Klammern übergeben, hier der gesamte Funktionsaufruf. Zusätzlich habe ich noch Labels ergänzt.


g2 = new Dygraph(
document.getElementById("graphdiv2"),
"test.csv", // path to CSV file
{ xValueFormatter: Dygraph.dateString_,
xValueParser: function(x) { return 1000*parseInt(x);},
xTicker: Dygraph.dateTicker,
labels: [ "Datum", "A0", "A1" ]
} // Options
);

Die Darstellung des Datums in der Grafik finde ich aber sehr ungünstig, habe mich aber nicht weiter damit beschäftigt, das zu verändern. Sinnvoller finde ich, die csv-Daten direkt mit einem interpretierbaren Datumsformat zu erzeugen. (Sorry, dass das nicht schon in Teil 3 berücksichtigt wurde). Hier die Änderung der php-Seite zur Ablage der Daten als csv-Datei, im Aufruf der Dygraph Funktion müssen jetzt natürlich die Optionen wieder entfernt werden.

<?php
isset($_GET['A0']) ? $a0=$_GET['A0'] : $a0='';
isset($_GET['A1']) ? $a1=$_GET['A1'] : $a1='';
$jetzt = time();
$delimiter = ",";
$enclosure = " ";
$handle = fopen("./test.csv", 'a');
fputcsv($handle, array(date("Y/m/d H:i:s",$jetzt),$a0,$a1),$delimiter,$enclosure);
fclose($handle);
?>

Doch nun zur Darstellung der Daten aus der MySQL Datenbank. Ich habe lange rumprobiert, wie man die Daten aus MySQL in den JavaScript Aufruf einbauen kann. Als Lösung habe ich die Daten innerhalb des JavaScript Aufrufs per php aus der Datenbank gelesen und als Array an die dygraphs Funktion übergeben. Die Daten müssen in genau dieser Form

[
[ new Date("2009/07/12"),100, 200 ],
[ new Date("2009/07/19"), 150, 220 ]
]

an dygraphs übergeben werden, deshalb sieht die Formatierung der Daten innerhalb der php-Funktion etwas chaotisch aus (siehe hier).

Folgende php-Seite sollte unter dem Namen graph.php auf dem Webspace erzeugt werden. Natürlich müssen wieder die Zugangsdaten der Datenbank eingetragen werden:

<html>
<head>
<body style="color: rgb(0, 0, 0); background-color: rgb(77, 77, 77)" alink="#ee0000" link="#0000ee" vlink="#551a8b">
<div style="text-align: center;"><span style="color: rgb(255, 255, 255);">Daten aus MySQL<br></span>
<br>
<script type="text/javascript"
src="dygraph-combined.js"></script>
</head>
<body>
<table style="margin:0px auto" border="0" width="500" align="center">
<tr>
<td style="background-color: #FFFFFF">
<div id="graphdiv2"
style="width:500px; height:300px;"></div>
<script type="text/javascript">

g2 = new Dygraph(document.getElementById("graphdiv2"),
<?php
$mysql_host = "<hier Name des Server/Host eintragen>";
$mysql_db = "<hier Datenbanknamen eintragen>";
$mysql_user = "<hier MySQL User eintragen>";
$mysql_pw = "<hier MySQL Passwort eintragen>";
$connection = mysql_connect($mysql_host, $mysql_user, $mysql_pw) or die("Verbindung zur Datenbank fehlgeschlagen.");
mysql_select_db($mysql_db, $connection) or die("Datenbank konnte nicht ausgewaehlt werden.");
$abfrage = "SELECT DATE_FORMAT(datum, '%Y/%m/%d %H:%i:%s') AS date, datum, analog0, analog1 FROM analog_data";       //   2009/07/12 12:34:56
$ergebnis = mysql_query($abfrage);
echo "[";                                  // start of the 2 dimensional array
while($row = mysql_fetch_array($ergebnis))
{
$utime = strtotime($row[datum]);
$diffutime = $utime - $lastutime;
if ($diffutime > 600) {
echo "["."new Date(\"".$row[date]."\")".",NaN,NaN],";
}
else {
echo "["."new Date(\"".$row[date]."\")".",".$row[analog0].",".$row[analog1]."],";
}
$lastutime = strtotime($row[datum]);
}
echo "]";
?> ,
{ rightGap: 20,
connectSeparatedPoints: true,
labels: [ "Datum", "A0", "A1" ] }          // options
);
</script>
</div>
</td>
</tr>
</table>
</body>
</html>

In der Übergabe des Arrays an die dygraph-Funktion habe ich eine Abfrage eingebaut, die dafür sorgt, dass (zeitliche) Lücken in der Datenreihe nicht als verbundene Punkte dargestellt werden.

Ich hoffe, diese Tutorial hat euch geholfen eure Daten zu speichern und grafisch zu präsentieren. Ich bin gespannt auf euer Feedback und eure Ergebnisse.

Tutorial: Speicherung von Arduino Messdaten auf Webserver und deren Darstellung – Teil 4

Teil 4 – Einrichten der MySQL Datenbank und speichern der Daten

In diesem Teil des Tutorials werde ich euch zeigen, wie man vom Arduino erzeugte Daten über Ethernet in einer MySQL Datenbank abspeichert. Eine Datenbank hat gegenüber der im vorherigen Beitrag angelegten csv-Datei viele Vorteile, z.B. dass die Daten bei der Abfrage bereits selektiert werden können (z.B. ein bestimmter Zeitraum) oder sortiert werden können. Ein Abfragebeispiel dazu werde ich in diesem Teil des Tutorials später vorstellen.

Die MySQL Datenbank und die Datentabelle muss zunächst auf dem Webspace angelegt werden, am einfachsten ist das über das Programm phpMyAdmin, dass auf den meisten Webspaces bereits installiert ist. Auf dem Webspace aus dem Teil 2 des Tutorials greift man darauf über die Administration des eigenen Webspaces zu. Dazu loggt man sich ein und wählt im linken Menue meine Projekte und dann das bereits angelegte Projekt. Auf dieser Seite scrollt man ganz nach unten und wählt dann unter Webspace MySQL. Die Zugangsdaten für MySQL werden später im Programm noch verwendet. Wenn noch keine Datenbank angelegt ist, muss man jetzt zunächst eine Datenbank anlegen.

Über den Link zu phpMyAdmin erreichen wir die Administration der Datenbank. Als nächstes legen wir eine Tabelle zur Speicherung der Daten an, Das geht am schnellsten mit einem SQL Statement. Zunächst wählt man links die Datenbank, dann den Reiter SQL und geben folgendes Statement ein

CREATE TABLE IF NOT EXISTS `analog_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`datum` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`analog0` int(11) NOT NULL COMMENT 'Analog0',
`analog1` int(11) NOT NULL COMMENT 'Analog1',
PRIMARY KEY (`id`)
)

das wir mit OK bestätigen. Mit diesem Statement wird eine Tabelle mitr dem Namen analog_data mit 4 Feldern (Spalten) angelegt, einer ID, die mit jedem Datensatz automatisch hochzählt, einem Zeitstempel, der bei Erzeugung eines neuen Datensatzes automatisch erzeugt wird und die beiden Messwerte analog0 und analog1.
Wenn keine Fehlermeldung kommt, ist die Tabelle, zunächst leer, jetzt angelegt.

Wie in Teil 3 benötigen wir jetzt zunächst eine php-Webseite die die Daten des Arduino annimmt und dann in der MySQL Tabelle abspeichert. Diese Seite legen wir unter dem Namen data2mysql.php an. Die Zugangsdaten (siehe Webspace Administrationsseite) müssen innerhalb der Anführungsstriche eingetragen werden. Der Name des Servers ($mysql_host) ist im Falle von kilu.de „localhost“.

<?php
$mysql_host = "<hier Name des Server/Host eintragen>";
$mysql_db   = "<hier Datenbanknamen eintragen>";
$mysql_user = "<hier MySQL User eintragen>";
$mysql_pw   = "<hier MySQL Passwort eintragen>";
isset($_GET['A0']) ? $a0=$_GET['A0'] : $a0='';
isset($_GET['A1']) ? $a1=$_GET['A1'] : $a1='';

$connection = mysql_connect($mysql_host, $mysql_user, $mysql_pw) or die("Verbindung zur Datenbank fehlgeschlagen.");
mysql_select_db($mysql_db, $connection) or die("Datenbank konnte nicht ausgewaehlt werden.");
$insert_data = "INSERT INTO analog_data (analog0, analog1) VALUES ($a0, $a1)";
mysql_query($insert_data, $connection) or die("Fehler beim Eintragen der Daten in die Datenbank!");
?>

Einen ersten Test können wir wie im 3. Teil auch mit dem direkten Aufruf der Webseite machen, also z.B.:  <webspace>/data2mysql.php?A0=123&A1=345

Mit phpMyAdmin kann man jetzt kontrollieren, ob die Werte korrekt übernommen wurden. Nun muss nur noch das Arduino Programm aus Teil 3 auf die neue php-Webseite umgestellt werden, also statt der Zeile

client.print("GET /data2csv.php?A0=");

wird jetzt

client.print("GET /data2mysql.php?A0=");

eingetragen.

Um sich die letzten Daten anzusehen reicht diese einfache php-Webseite, wobei wieder die Zugangsdaten der Datenbank eingetragen werden müssen.

<?php
$mysql_host = "<hier Name des Server/Host eintragen>";
$mysql_db   = "<hier Datenbanknamen eintragen>";
$mysql_user = "<hier MySQL User eintragen>";
$mysql_pw   = "<hier MySQL Passwort eintragen>";
$connection = mysql_connect($mysql_host, $mysql_user, $mysql_pw) or die("Verbindung zur Datenbank fehlgeschlagen.");
mysql_select_db($mysql_db, $connection) or die("Datenbank konnte nicht ausgewaehlt werden.");
$abfrage = "SELECT datum, analog0, analog1 FROM analog_data ORDER BY datum DESC LIMIT 20";
$ergebnis = mysql_query($abfrage);
while($row = mysql_fetch_array($ergebnis))
{
echo $row[datum].",".$row[analog0].",".$row[analog1]."<br>";
}
?>

In dieser Abfrage wird die oben erwähnte Selektion, hier der letzten 20 Datensätze und eine Sortierung angewendet. Im nächsten und letzten Teil des Tutorial beschäftigen wir uns dann mit der grafischen Präsentation der Daten.

Tutorial: Speicherung von Arduino Messdaten auf Webserver und deren Darstellung – Teil 3

Teil 3 – Speichern von Daten auf dem Webspace

In diesem Teil des Tutorials werden wir Daten, die der Arduino misst, auf einem Webserver als CSV-Datei ablegen. Wichtig ist dabei zu verstehen, wie Daten an einen Webserver übergeben werden können. In diesem Beispiel nutze ich das HTTP GET Protokoll. Im HTTP GET Protokoll werden die Daten in der Adresszeile des Browsers übergeben. Hier einmal ein einfaches Beispiel:  http://erniberni.kilu.de/name.php?Name=Reinhard Der Aufruf übergibt den Parameter Name mit Inhalt Reinhard. Kopier den Link und gibt etwas anderes ein.

Die Datei name.php auf dem Webspace sieht so aus:

<?php
isset($_GET['Name']) ? $name=$_GET['Name'] : $name='';
echo "Hallo, guten Tag ".$name;
?>

Das Programm dahinter ist sehr einfach. Wenn der Parameter Name gesetzt ist (isset), dann lade den Parameter in die Variable $name, falls er nicht gesetzt ist, lade die Variable mit einem leeren String.

Ich hoffe damit ist das Prinzip der Datenübergabe klar geworden. Als nächstes wollen wir mit dem Arduino Daten an den Webspace übertragen. Dazu nutzen wir ein Programm, dass ganz ähnlich ist zum WebClock Programm aus dem ersten Teil. Doch zunächst legen wir die php Seite an, die die Daten empfängt. Auf dem Webspace legen wir eine Datei mit dem Namen data2csv.php mit folgendem Inhalt an.

<?php
isset($_GET['A0']) ? $a0=$_GET['A0'] : $a0='';
isset($_GET['A1']) ? $a1=$_GET['A1'] : $a1='';
// echo "eingegeben wurde: ".$a0." und ".$a1; //your php code here
$jetzt = time();
$handle = fopen("./test.csv", 'a');
fputcsv($handle, array($jetzt,$a0,$a1));
fclose($handle);
?>

Wenn diese Seite mit Parametern für A0 und A1 aufgerufen wird, werden diese Werte mit einem Zeitstempel in eine Datei test.csv auf dem Webspace abgelegt. Über die Browserzeile kann das jetzt schon mal getestet werden. Der Aufruf lautet z.B. <webspace>/data2csv.php?A0=123&A1=345 . Den gespeicherten Inhalt kann man sich ansehen durch Aufruf der Datei auf dem Webspace, also <webspace>/test.csv . Das das keine darstelbare Webseite ist, fragt der Browser, ob die Datei gespeichert oder geöffnet werden soll. Der Inhalt der Datei sollte jetzt z.B. so aussehen:

1399410041,124,345

Der erste Wert ist ein Unix Timecode und steht für die Anzahl der Sekunden seit 1.1.1970 0:00. Weiter geht es jetzt mit dem Arduino Code zur Speicherung der Werte. Im Code muss dann noch die eigene IP-Adresse des Ethernetshield und der Name des Webspaces eingetragen werden.

/* This sketch is based on:
Repeating Web client

This sketch connects to a web server and makes a request
using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or
the Adafruit Ethernet shield, either one will work, as long as it's got
a Wiznet Ethernet module on board.

Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13

created 19 Apr 2012
by Tom Igoe, modified by Reinhard Nickels 15.02.2014

http://arduino.cc/en/Tutorial/WebClientRepeating
This code is in the public domain.

*/

#include <SPI.h>
#include <Ethernet.h>

// assign a MAC address for the ethernet controller.
// fill in your address here:
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// fill in an available IP address on your network here,
// for manual configuration:
IPAddress ip(192,168,2,99);      // <- hier die IP des Ethernet Shield eintragen

// initialize the library instance:
EthernetClient client;

char server[] = "<name webspace>";      //  <- hier Name des Webspaces eintragen

unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
boolean lastConnected = false;                 // state of the connection last time through the main loop
const unsigned long postingInterval = 60000;  // das ist ein Bug im Beispiel -> http://forum.arduino.cc/index.php/topic,125510.0.html

void setup() {
// start serial port:
Serial.begin(115200);
// give the ethernet module time to boot up:
delay(1000);
// start the Ethernet connection using a fixed IP address and DNS server:
Ethernet.begin(mac, ip);
// print the Ethernet board/shield's IP address:
Serial.print("My IP address: ");
Serial.println(Ethernet.localIP());
}

void loop() {
// if there's incoming data from the net connection.
// send it out the serial port.  This is for debugging
// purposes only:
if (client.available()) {
char c = client.read();
Serial.print(c);
}

// if there's no net connection, but there was one last time
// through the loop, then stop the client:
if (!client.connected() && lastConnected) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
}

// if you're not connected, and ten seconds have passed since
// your last connection, then connect again and send data:
if(!client.connected() && (millis() > lastConnectionTime + postingInterval)) {
httpRequest();
}
// store the state of the connection for next time through
// the loop:
lastConnected = client.connected();
}

// this method makes a HTTP connection to the server:
void httpRequest() {
// if there's a successful connection:
Serial.println("try connecting...");
if (client.connect(server, 80)) {
Serial.println("connecting...");
// send the HTTP PUT request:
client.print("GET /data2csv.php?A0=");
client.print(analogRead(A0));
client.print("&A1=");
client.print(analogRead(A1));
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();

// note the time that the connection was made:
lastConnectionTime = millis();
}
else {
// if you couldn't make a connection:
Serial.println("connection failed");
Serial.println("disconnecting.");
client.stop();
}
}

Die Kontrolle der abgelegten csv Datei kann dann wie oben erfolgen. Sehr viel eleganter ist das allerdings, wenn die csv Datei durch den Aufruf einer Webseite angezeigt wird. Dafür legen wir uns eine php Seite, die z.B. unter dem Namen showdata.php an.

<?php
// $row = 1;     // optional kann durch weglassen der Auskommentierung eine Zeilennummer angezeigt werden.
if (($handle = fopen("test.csv", "r")) !== FALSE) {
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
        $num = count($data);
//        echo "<p> $num Felder in Zeile $row: <br /></p>\n";
//        $row++;
        for ($c=0; $c < $num; $c++) {
            if ($c < 1) {
                $datum = date("m.d.y H:i:s", $data[$c]);
                echo $datum." ";
                }
            else {
                echo $data[$c]." ";
            }
        }
        echo "<br>";
    }
    fclose($handle);
}
?>

Diese Seite liest die Datei Zeile für Zeile ein und gibt den Inhalt als Text aus, Das Datum wird dabei in eine lesbare Form umgewandelt. Der Aufruf erfolgt über <webspapce>/showdata.php .

In der nächsten Folge dieses Tutorial geht es dann weiter mit Anlage einer MySQL Datenbank und die Speicherung der Daten darin.

Tutorial: Speicherung von Arduino Messdaten auf Webserver und deren Darstellung – Teil 2

Tutorial Teil 2 – Anlegen eines kostenlosen Webspace

Für die Speicherung der Logging Daten benötigen wir einen Server mit Webserver inklusive PHP und MySQL Datenbank. Natürlich kann man sich einen Webserver sehr einfach z.B. auf einem Linux Rechner oder einem RaspberryPi installieren, aber diese Server müssen immer eingeschaltet sein. Als eine reizvolle Alternative gibt es  verschiedene Anbieter im Markt, die Webserver mit MySQL kostenlos anbieten. Unter chip.de findet man eine Liste der Anbieter.

Ich habe mir hier den Anbieter kilu.de ausgesucht, weil angeblich werbefrei 10GB Speicherplatz und unlimitierter Traffic versprochen wird. Die Anmeldung verläuft problemlos.

Aktualisierung 17.07.2015 Leider ist kilu.de ab dem 01.08.2015 kostenpflichtig. Die Anleitung gilt sinngemäß natürlich auch für andere Webspaces. Die angegebenen Links auf meinen Webspace bei kilu.de werden deshalb nicht mehr funktionieren.

kilu

 

Die Anmeldung erfordert die Angabe der persönlichen Daten, die sicherlich zu Werbezwecken weiterverwendet werden. Nach Angabe der Daten erhgält man eine Bestätigungmail mit den Zugangsdaten. Bein ersten Login sollte man das Passwort ändern. Man wir zur Eingabe einer Mobilnummer aufgefordert, über die dann ein Bestätigungcode gesendet wird, der eingegeben werden muss.

Als erstes richten wir den Webspace ein, das geht über „neues Projekt“ und „Webspace erstellen“. Nach Angabe von Titel und Beschreibung kann man den Webspace einer Kategorie zuordnen.

kilu3Die zuvor gewählte Subdomain wird übernommen. Die Einrichtung des Webspaces dauert bis zu 15 min. Nach kurzer Zeit ist der neue Webspace unter „meine Projekte“ sichtbar. Zur Konfiguration muss man dann ganz nach unten auf die Seite scrollen. Ganz unten findet man dann die Zugangsdaten für FTP und MySQL. Leider ist die Seite doch nicht werbefrei, wie sich jetzt zeigt. Nachdem auch MySQL aktiviert ist, können die Zugangsdaten der Dienste notiert werden. Wir benötigen für FTP: Server, Benutzer, Passwort und für MySQL: Server/Host, Benutzer, Passwort. Insgesamt sind 3 Datenbanken möglich.

Über phpMyAdmin können die Datenbanken und Tabellen sehr einfach gepflegt werden. In einem späteren Tutorial werde ic die Anlage von Tabellen zeigen. Mit einem FTP-Client seiner Wahl kann man sich dann mal ansehen, was schon auf dem Webspace liegt. Man kann natürlich auch seinen Webspace schon mal aufrufen.

Als erstes sollte man sich mal per FTP in das Verzeichnis www eine Datei mit dem Namen phpinfo.php und folgendem Inhalt kopieren

<?php
phpinfo();
?>

Über den Aufruf <webspacename>/phpinfo.php kann man sich dann ansehen, was der Webserver so leistet.

Wer das Beispiel aus Teil 1 des Tutorials zur Ausgabe der Uhrzeit jetzt auf seinem eigenen Webspace anlegen möchte, muss nur eine  Datei unter dem Namen clock.php mit folgendem Inhalt in das www Verzeichnis seines Webspaces legen und im Arduino Programm bei char server[]= den Servernamen eintragen.

<?php
echo "Es ist ".date('H:i:s');
?>

Im nächsten Teil dieser Tutorial Reihe (coming soon) geht’s dann weiter mit der Anlage einer Webseite über die ich Daten per Arduino als WebClient ablegen kann.

 

 

 

Tutorial: Speicherung von Arduino Messdaten auf Webserver und deren Darstellung – Teil 1

Einführung

Es ist immer wieder das selbe Problem:

Da entwickelt man ein Program für den Arduino zur Messung von irgendwelchen Daten. Solange der Computer angeschlossen ist, kann man die Daten über die serielle Schnittstelle als Text darstellen. Um diese Daten dann grafisch darzustellen, kann man die Daten z.B. nach Excel kopieren. Das ist aber umständlich und letzendlich nur eine Momentaufnahme der Messung.
Doch was, wenn der Arduino ohne Computer weiter messen soll?
Eine mögliche Lösung wäre die Speicherung der Daten auf einer SD-Karte. Es gibt günstige Shields mit SD Kartenslot und auch das Ethernet Shield hat einen SD Slot. Aber auch hier muss man die Messung unterbrechen und die Daten der SD Karte im Computer weiterverarbeiten.

Das alles ist umständlich und außerdem will ich an meine Daten ohne in der Nähe meines Arduinos zu sein. Die Lösung ist die Speicherung der Daten auf einem Webserver und der Abruf der Daten von irgendeinem Rechner oder Tablett über das Internet.

In diesem Tutorial werde ich in mehreren Schritten zeigen, wie Daten nur von einem Arduino mit Ethernetshield auf einen Webserver abgelegt werden und sich von dort grafisch aufarbeiten lassen. Hier ein kleiner Vorgeschmack was euch in diesem Tutorial erwartet. (edit: leider hat sich der Betreiber funpic.de aufgelöst, der Link funktioniert deshalb nicht mehr. Ich werde das Beispiel in Kürze auf eine andere Webseite nehmen).

funpic1

Diese Daten liegen auf einem kostenlosen Webspace von Funpic.de . Der Anbieter finanziert sich mit Werbung, die aufpoppenden Fenster muss man leider dafür billigend in Kauf nehmen. In die Messwerte kann man durch Markieren eines Bereiches mit der Maus reinzoomen. Nach dem Durcharbeiten dieses Tutorial bist du in der Lage, deine Daten ebenso darzustellen.

Im ersten Teil dieses Tutorial gehe ich darauf ein, wie Daten vom Arduino mit Ethernetshield an einen Webspace gesendet werden. Im zweiten Teil werden wir dann einen freien Webspace einrichten und eine einfache Webseite anlegen. Im dritten Teil geht es dann um das Ablegen der Messdaten in einer CSV Datei. Der vierte Teil beschreibt die Konfiguration einer MySQL Datei und das Speichern der Daten darin. Im letzten Teil werden wir uns dann mit der grafischen Darstellung der Daten beschäftigen.

Teil 1 – Verbindung mit Webspace

Ich benutze für meine Experimente ein Ethernetshield mit Wiznet Chipsatz, die man inzwischen sehr günstig bekommen kann. Eine genaue Beschreibung findet man hier. Mit diesem Shield kann man die Beispiele aus der Arduino IDE verwenden, z.B. in der Arduino IDE über das Menü. Datei->Beispiele->Ethernet->WebClient. Ich habe dieses Beispiel geringfügig verändert und lade damit die aktuelle Zeit von einer von mir entsprechend vorbereiteten Webseite. Das Beispiel kann so übernommen werden, lediglich die IP des Ethernet Shield muss angepasst werden. Der Arduino verbindet sich mit der Webseite und liest deren Inhalt (in diesem Fall die aktuelle Zeit) und gibt ihn seriell aus. Sicher nichts spektakuläres, aber man könnte damit unter Verwendung des Time Libraries die Uhrzeit stellen und Gangungenauigkeiten ausgleichen. Natürlich geht das auch über NTP, soll aber hier als Beispiel für den Aufruf einer Webseite dienen.

/*
  WebClock by Reinhard Nickels
 
 This sketch connects to a website
 using an Arduino Wiznet Ethernet shield.
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 
 based on WebClient (arduino Examples)
 by David A. Mellis, by Tom Igoe, based on work by Adrian McEwen
  */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
char server[] = "rncologne.rn.funpic.de";    // <-  wenn du das auf deinem eigenen Server machen willst, muss das hier geändert werden

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192,168,2,99);       // <- an dieser Stelle die IP des Ethernet Shield eintragen, ich habe eine feste Adresse vergeben.

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

void setup() {
 // Open serial communications and wait for port to open:
  Serial.begin(115200);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // start the Ethernet connection:
  Ethernet.begin(mac, ip);
  // give the Ethernet shield a second to initialize:
  delay(1000);
  // print the Ethernet board/shield's IP address:
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());

  Serial.println("connecting...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected");
    // Make a HTTP request:
    client.println("GET /clock.php HTTP/1.1");
    client.print("Host: ");
    client.println(server);
    client.println("Connection: close");
    client.println();
  }
  else {
    // kf you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}

void loop()
{
  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

    // do nothing forevermore:
    while(true);
  }
}

Die Ausgabe seriell sieht dann z.B. so aus:

My IP address: 192.168.2.99
connecting...
connected
HTTP/1.1 200 OK
Server: Apache
Set-Cookie: notabotxxx=775e1282fb3146e7de81e2f8f769d433; expires=Sun, 11-May-2014 18:31:16 GMT; path=/; domain=..
Vary: Accept-Encoding
Content-Type: text/html
X-Funpic-Backend-ID: webfree_071
Content-Length: 15
Accept-Ranges: bytes
Date: Sun, 11 May 2014 17:31:19 GMT
Via: 1.1 varnish
Connection: close
X-Funpic-ID: 1392478474
X-Funpic-Age: 0
X-Funpic-Host: rncologne.rn.funpic.de
X-Funpic-Backend: fp_storage_07
X-Funpic-Cache: MISS

Es ist 19:31:16
disconnecting.

Im zweiten Teil dieses Tutorials geht es dann um die Konfiguration eines kostenlosen Webspaces.

Temperatur und Feuchtemessung mit 868 MHz Funksensor

Für die Räume der DingFabrik Köln sollte eine drahtlose Erfassung von Temperatur und Feuchte innen und außen an mindestens 4 Meßstellen aufgebaut werden. Viele Versuche mit 433 MHz Sensoren und Sendern, z.B. dem KW-9010 als Sensor mit Sender oder einem Selbstbau mit ATTiny85 mit 433 MHz endeten alle mit dem Ergebnis, dass die Reichweite zu gering war. Insbesonders dann wenn die Empfänger mit einem Raspberry Pi kommunizierten gab es Störungen insbesonders durch schlechte Masseführung. Nach etlichen Versuchen konnte ich mit dem TinyTX auf 868MHz eine gute Reichweite und hohe Stabilität erreichen. Dieses Modul sendet mit dem RFM12B auf FSK Modulation ist von daher weniger störanfällig (UKW ist eben besser als MW ;-) ). In einem separaten Blogpost beschreibe ich den Empfänger. In weiteren Blogposts wird beschrieben, wie ich die Daten in einer RRD Datenbank speichere und per Webinterface grafisch darstelle.

Die TinyTX Lösung sendet neben der Temperatur und der Feuchte, gemessen mit einem DHT22 zusätzlich die Versorgungsspannung. Damit wird ein Batteriewechsel gut planbar. Die Platine braucht extrem wenig Strom, da die Software den Sleep Modus nutzt. Momentan nutze ich LiIon Akkus mit einer Diode in Reihe (damit ca. 3,2 – 3,8V). Der DHT22 braucht mindestens 3V, sinkt die Versorgungsspannung darunter, werden falsche Feuchtewerte gemessen. Die Software von Nathan habe ich geringfügig angepasst und übertrage zusätzlich die Minuten seit dem letzten Reboot. Den Code findet ihr auf Github.

 

 

Hier noch ein Foto des Fehlversuchs mit DHT22, billigem China Sender und ATTiny85.

Der KW9010 enthält letztendlich auch nur einen billigen China Sender.

 

 

 

 

 

 

 

 

 

 

 

 

Raspberry Pi empfängt auf 868 MHz

Für mein Projekt „Temperatur und Feuchte per Funk“, das die Sendemodule von Nathan Chantrells TinyTX nutzt, war ich auf der Suche nach einem geeigneten Empfänger, der die Daten auf einen Raspberry Pi bringt, wo sie letztendlich gespeichert werden sollen und per Webseite dargestellt werden.

Im ersten Schritt setzte ich die RPi-Shield-Bridge von Watterott ein, quasi ein vollständiger Arduino Clone auf einem Board, dass auf den Pinheader des Raspberry Pi gesteckt werden kann. Das RPi-Shield hat den Vorteil, dass bereits Pegelwandler 5V<-> 3,3V für die Kommunikation zwischen RaspPi und Arduino enthalten sind. Weiterer Vorteil sind die Arduino Shield kompatiblen Buchsenleisten.

Bild

Raspberry Pi mit RPi-Shield Bridge, Proto-Shield und RFM12B

Für meinen ersten Testaufbau benutze ich zusätzlich ein Proto-Shield auf dem ein RFM12B mit 868MHz als Empfänger steckt.

Nachdem die Software und Hardware zuverlässig funktionierten, wollte ich eine elegantere Lösung finden. Meine ersten Recherchen führten mich zum Raspberry Pi Base Station Receiver Board des Projektes OpenEnergyMonitor. Dieses Board erfüllte alle meine Anforderungen. Da ich allerdings noch einige Arduino Mini Clones rumliegen hatte, entschied ich, ein eigenes Board zu designen. In Eagle entstand eine doppelseitige Platine, die nur  8 Durchkontaktierungen hat und sich deshalb relativ leicht selbst herstellen lässt. Da nicht alle Anschlüsse des Mini benutzt werden, müssen auch nicht alle Bohrungen gemacht werden.

Eagle Layout Arduino Mini Raspberry Bridge 868MHz

Eagle Layout Arduino Mini Raspberry Bridge 868MHz

IMG_1819

Raspberry Pi mit Arduino Mini Bridge 868MHz

Für erste Tests wurde aus der WiringPi Library das SerialRead Beispiel benutzt. Zum Arduino Mini ist noch zu bemerken, dass es Versionen mit 5V oder mit 3,3V Versorgungsspannung gibt. Die 5V Versionen laufen bei mir auch mit 3,3V, allerdings läuft dann der ATMega mit 16MHz außerhalb seiner Spec. Wenn das Probleme bereitet, werde ich den Prozessor auf 8MHz internen Takt umfusen.

Einrichtung des Raspberry Pi, um Daten seriell zu empfangen

Im Raspbian Image für den Pi ist die serielle Schnittstelle standardmäßig als serielles Terminal konfiguriert. Das muss zunächst umgestellt werden.

$ sudo nano /boot/cmdline.txt

console=ttyAMA0,115200     und     kgdboc=ttyAMA0,115200   löschen

$sudo nano /etc/inittab

Die Zeile auskommentieren oder löschen     T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100.

Den Raspberry rebooten.

Die Installation von WiringPi wird hier erklärt.

Die Eagle Files liegen auf Github.