Arduino <-> Raspberry <-> MySQL Serial Communication

Frohe Ostern!

Erstmal das Problem schildern:
Weiß nicht wie ich es anstellen soll XD

Aufgabe:
Es gibt ein Slave (AtTiny84), Master (Arduino Mega) und den berühmten Raspberry Pi.
Der Master ist mit dem RPi über USB Kabel verbunden und soll mithilfe von Serial Daten hin und her schicken.
Wenn der Master resettet wird, sollen Daten aus der MySQL Datenbank auf dem Master geladen werden.
Der RPi hat immer die Aktuellen Daten aus der Datenbank (oder state.json Datei, da JSON und jQuery eingesetzt wird).
Auf dem RPi läuft ein Webserver.
Wenn der Slave über RS485 an den Master den LED zustand sendet, soll auf dem Master dieser gemerkt werden und an den RPi über Serial gesendet werden. Der RPi leitet dann den Zustand an die Datenbank.
Wenn man über den Browser ein Switch umschaltet, soll an den Master über Serial der neue Zustand gesendet werden, der Master sendet diesen über RS485 an den Slave weiter und anschließend soll der Master in die Datenbank den neuen Zustand speichern.

Da der Master kein Ethernet Shield hat, weiß ich nicht wie der Master an die Datenbank rankommen soll.
Denke es soll eine Antwort vom Master zum RPi zurückkommen, wenn über Browser ein Switch umgelegt wird und der RPi schreibt dann in die Datenbank.

Ich habe hier schon was gefunden, wo die Verbindung zum Arduino steht und die LEDs geschaltet werden können.
Blos da wird der Zustand nicht gespeichert, alle meine Versuche schlugen fehl.

Hat einer eine bessere Idee wie man das ganze realisieren könnte, wo auch der Zustand gespeichert wird nach einem Reset?
Oder mir bei dieser Umsetzung helfen? Gibts 100%tig noch andere die sowas Vorhaben oder schon Realisiert haben.

ardudome.zip (11.8 KB)

Grundlegend hat der Ansatz vom "Ardudome" Projekt das Problem das alle Aktionen von den PHP-Scripten initiiert werden und somit immer ein Browser auf die Seite zugreifen muss, sonst passiert nix.

Was Du möchtest ist aber, das der Arduino den Raspberry über eine ständig (oder mindestens beim Starten) aktive serielle Verbindung ansprechen kann. Das geht aber nur, wenn auf dem Raspberry jederzeit irgendein Programm auf der seriellen Schnittstelle lauscht, ob der Arduino Anfragen schickt. Denn der Raspberry kann ja nicht "wissen" wann der Arduino gerade mal einen Reset bekommt.

Das ist ein ganz anderes Konzept. Das würde ich mit einem zusätzlichen Programm / Script auf dem Raspberry lösen, das als "Middleware" eine Schnittstelle zwischen der seriellen Konsole des Arduino und z.B. einem TCP-Socket auf dem Raspberry bereit stellt.
Mario.

Ich schreib gerade so eine Software.
Auf dem Raspberry Pi ist, falls man Rasbian verwendet, python installiert.

Bei mir lauscht ein Python Programm durchgehend ob vom Arduino etwas kommt. Sobald etwas da ist, wird dieses in eine Mysql Datenbank geschrieben, direkt über Python.

Auf die Datenbank greift dann PHP zu und verarbeitet alle Daten die als neu gekenzeichnet sind, sobald der Webbrowser aufgerufen wird. Wenn kein User zugreift schreibt das Python Script dauerhaft Daten.

Bei Interesse können wir bei dem Projekt zusammen arbeiten. Ich habe bei mir auf dem Raspberry noch die Klassenbiliothek Qt installiert mit der sich sehr einfach grafische Obferlächen erstellen lassen.

Jomelo:
Bei Interesse können wir bei dem Projekt zusammen arbeiten.

Sehr gerne :wink:

Wie ist es denn in der Datenbank, werden da immer wieder neue Werte geschrieben oder die alten auch gelöscht?
Weil nachher hab ich da millionen von Werten die wertlos für mich sind.

Python ist für mich Neuland, noch nix mit zu tun gehabt. Werd wohl nicht drumherum kommen können.

Das kann man handhaben wie man will, je nach Anwendung ist es sinnvoll daten auch zu löschen oder Eben nicht.
Mysql hat keine Probleme damit 4 Mio Werte in einer Tabelle zu haben, erst danach wirds komplizierter :wink:

Python ist wesentlich leichter als C oder C++. Wohl vergleichbar mit PHP da es auch keinen Kompliler benötigt. Zudem gibt es keine Klammern. Die Ebene in der der Code Strukturiert wird, wird über das Einrücken des Codes bestimmt, also mit Tabs und das Simikolon benötigt man auch nicht mehr.

Welches Betriebssystem verwendest du auf dem Raspberry ?

Raspbian wheezy.
Aber mir ist es egal welches System da drauf läuft, hauptsache es liefert gute Ergebnisse :slight_smile:
Apache2, MySql, PhpMyadmin, PHP5 und Proftp läuft zurzeit.
Hab den Raspberry erst seit einer Woche aber mit Ubuntu hab ich paar Server am laufen gehabt.

So, hat ein wenig gedauert, aber bei mir läufts nun.

Logischer Aufbau:

Programmablauf:

  1. String wird auf der Internetseite eingegeben
  2. PHP Script trägt String in Datenbank ein
  3. Python Script ließt String aus Datenbank aus und überträgt über USB den String an den Arduino
  4. Der Arduino ließt den String komplett ein while Serial.read ...
  5. Der eingelesene String wird mit Serial.write wieder gesendet
  6. Das Python Script emfängt die Daten und schreibt diese in einem neuen Eintrag in die Datenbank
  7. Auf der Internetseite werden die Empfangenen Daten des Arduino angezeigt.

Vorbereitung Rasbperry Pi:

  1. z.B. mit dem Tool Noobs ein Betriebssystem mit Oberfläche installieren
  2. Webserver Installieren, PHP5, Mysql, phpmyadmin, ftp-server,
  3. VNC Server installieren (sudo apt-get install tightvncserver) für Virtuellen Desktop
  4. Python 2.7 installieren
  5. Datenbanktreiber für Python installieren (sudo apt-get install python-mysqldb)
  6. Schnittstellentreiber für die Serielle Schnittstelle installieren (sudo apt-get install python-serial)
  7. Arduino mit dem Raspberry Pi per USB Verbinden
  8. in phpmyadmin eine Datenbank mit dem Namen "test_db" erstellen

in der neuen Datenbank folgen SQL code einfügen:

CREATE TABLE IF NOT EXISTS `test_table` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `to_arduino` varchar(200) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `from_arduino` varchar(200) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `status` tinyint(1) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `status` (`status`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Auf den Arduino entweder vom PC / Laptop aus oder über die Arduino IDE auf dem Raspberry folgenden Code aufspielen:

void setup()
{
  Serial.begin(9600);
}

char str[250];
uint8_t str_cnt = 0;

void loop()
{  
  if(Serial.available()) {
    str[str_cnt] = Serial.read();
    str_cnt++;    
  }
  
  if(str_cnt > 0) {
    Serial.write(str);
    str_cnt = 0;
  }    
}

Auf dem Webserver sollte eine PHP Datei mit folgendem Inhalt erstellt werden:

<?php
header("Content-Type: text/html; charset=utf-8");

$display_errors = true;

if($display_errors == true) {
	ini_set('display_errors', '1');
	error_reporting(E_ALL);
} else {
	ini_set('display_errors', '0');
	error_reporting(0);
}

$db_host = 'localhost';
$db_user = 'root';
$db_pass = 'password';   // <-------- anpassen
$db_name = 'test_db';

$DBH = new PDO('mysql:host='.$db_host.';dbname='.$db_name, $db_user, $db_pass);

//Daten in Datenbank eintragen
$send = '';
if (isset($_POST['send_to_arduino'])) {
	$value = trim($_POST['send_to_arduino']);
	if(!empty($value)) {
		$sth = $DBH->prepare("INSERT INTO test_table (to_arduino, status) VALUES (:to_arduino, 1)");
		$sth->bindParam(':to_arduino', $_POST['send_to_arduino']);
		$sth->execute();
		$send = "String: '".$_POST['send_to_arduino']."' gesendet
";
	}
}

// Warten das Daten Empfangen Werden
sleep(1);

$empfangen = '';
// Daten Empfangen
$sth = $DBH->prepare("SELECT id, from_arduino, status FROM test_table WHERE from_arduino != ''");
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_ASSOC);
if(count($result) > 0) {
	// Daten Vorhanden
	$new = '';
	$old = '';
	foreach($result AS $key => $row) {
		if($row['status'] == 1) {
			$new .= "- empfangen: '".$row['from_arduino']."'
";
		} else {
			$old .= "- empfangen: '".$row['from_arduino']."'
";
		}
		// Daten als alt makieren
		$sth = $DBH->prepare("UPDATE test_table SET status=0 WHERE id=:id");
		$sth->bindParam(':id', $row['id']);
		$sth->execute();	
	}	
	$empfangen = "<b>Neue Dinge:</b>
".$new."

<b>Alte Dinge:</b>
".$old;
}
?>

<html>
	<head><title>Test Script</title></head>
	<body>
		<form action="test_db.php" method="post">
			String zum Senden eingeben: <input type="text" name="send_to_arduino" />

			

			<input type="submit" value="Senden" />
			<?php echo $send; ?>
		</form>
		
		<?php echo $empfangen; ?>
	</body>
</html>

In der Datei muss unter $db_pass das Passwort der Datenbank eingetragen werden.

Auf dem Raspberry Pi muss eine Python Datei erstellt werden (z.B. test_python_db.py), in der folgender Quellcode eingefügt wird:

import time
import serial
import MySQLdb as mdb

# configure the serial connections (the parameters differs on the device you are connecting to)
ser = serial.Serial(
    port='/dev/ttyUSB0',
    baudrate=9600,
    parity=serial.PARITY_ODD,
    stopbits=serial.STOPBITS_TWO,
    bytesize=serial.SEVENBITS
)

db_host = 'localhost'
db_user = 'root'
db_pass = 'password'   # <--------------------- diese Zeile anpassen
db_name = 'test_db'

ser.open()
ser.isOpen()

while True:
    # Zum Arduino senden
    # Ueberpruefen ob neue Daten in Datenbank, dann diese Senden
    try:
        con = mdb.connect(db_host, db_user, db_pass, db_name);
        cur = con.cursor()
        # Abfrage
        cur.execute("SELECT id, to_arduino FROM test_table WHERE to_arduino != '' and status = '1'")
        # Ergebnis
        rows = cur.fetchall()
        # Zerlegen und Senden, eventuell mit Zeitverzgerung von 100 ms damit
        # damit der Arduino Zeit zum verarbeiten hat
        if len(rows) > 0:
            for row in rows:
                string = str(row[1]) + '\r\n'
                ser.write(string)
                # Datensatz deaktivieren oder loeschen
                cur = con.cursor()
                cur.execute("UPDATE test_table SET status=0 WHERE id=%s", row[0])
                con.commit()
            print "Daten gesendet"
    except mdb.Error, e:
        print "Error %d: %s" % (e.args[0],e.args[1])
        sys.exit(1)


    # Vom Arduino empfangen
    out = ''
    while ser.inWaiting() > 0:        
        out += ser.read()

    if out != '':
        #Daten in Datenbank schreiben
        try:
            con = mdb.connect(db_host, db_user, db_pass, db_name);
            cur = con.cursor()
            cur.execute("INSERT INTO test_table (to_arduino, from_arduino, status) VALUES ('', %s, 1)", out)
            con.commit()
            print "Daten empfangen"
        except mdb.Error, e:
            if con:
                con.rollback()
            print "Error %d: %s" % (e.args[0],e.args[1])
            sys.exit(1)

    time.sleep(0.5)

Die Python Datei kann dann über die Python IDE ausgeführt werden, oder direkt über die Konsole (python pfad/datei.py)
Falls euer Programm im Autostart mit geladen werden sollte, sollten alle print Ausgaben im Quellcode deaktiviert werden.

Mit dem Script ist es auch durch leichte Änderungen mögilch in der Datenbank eine Uhrzeit zu speichern, sprich Ihr könnt über die Website einstellungen vornehmen die zu einer gewissen Uhrzeit erst zum Arduino gesendet werden.

Falls ihr noch Fragen zu einigen Schritten habt, ich kann auch alles detailierter erklären, aber jedem sollte bewusst sein, dass dieses Vorhaben nichts für blutige Anfänger ist :wink:

Diesen Beitrag bitte nicht löschen, falls oben der Platz nicht mehr reicht :wink:

Als erstes, Vielen Herzlichen Dank für die mühe, egal obs bei mir nachher klappt oder nicht :smiley:

Nach dieser Anleitung habe ich den Server aufgesetzt:
http://www.renehering.de/2013/12/raspbian-auf-einem-raspberry-pi-installieren/

Dazu habe ich:
2014-01-07-wheezy-raspbian.img und ApplePi-Baker benutzt.

Jomelo, was hälst du von Webmin?
Hatte es damals auf dem PC der als Server lief.
Auch kurz auf dem Raspberry drauf gehabt.

Webmin und ApplePi-Baker hab ich bisher noch nie verwendet, bzw davon gehört.

Ich hab das Image auf dem Raspberry mit NOOBs installiert. Als Betriebssystem läuft bei mir Raspian. Neben Python habe ich noch OpenCV als Bildverarbeitungsbibliothek installiert (das kompilieren dauert 11 Stunden). Zudem noch Qt, da ich auch mit Grafischen Oberflächen ab und zu arbeite.

Die Installationsanleitung für phpmyadmin und co hab ich auch verwendet, wobei im Moment läuft aus Testzwecken bei mir kein Apache sondern der lighttpd Webserver. Große unterschiede hab ich noch nicht festgestellt.

Ich hab ja laut der Anleitung alles für das GUI entfernt, dann kann ich auch die Python IDE nicht nutzen, will ich auch nicht.

  1. VNC Server installieren (sudo apt-get install tightvncserver) für Virtuellen Desktop
  2. Python 2.7 installieren

Ich will das Script im Autostart drin haben, dazu brauch ich ja die IDE nicht, oder?
Dann reicht auch python-mysqldb und python-serial.
lighthttpd wollte ich gestern auch draufschmeißen, dann doch lieber gelassen, wollte allen möglichen ärger wegen Inkompatibilität oder ähnlichem vermeiden.

PS: Das NOOBS hört sich für mich an wie als obs extra für NOOBS gemacht wurde :smiley: :smiley: :smiley:

NOOBs funktioniert dafür wunderbar :wink:
Ich hatte nie Lust mich mit allen Systemen herumzuschlagen, lieber ein fertiges nutzen. Die GUI brauchst du so an sich nicht. Das Script sollte nur mit python script.py ausführbar sein. Am leichtesten kann man das testen mit einer Datei die nur print "hello world" enthält, das sollte nach dem aufruf dann in der Konsole stehen. Die IDE gibt einem noch genauerere Fehlerinformationen als die Konsole, aber ansich sollte das laufen.

So ich bin morgen abend wieder erreichbar. 8)

/var/www/test_python_db.py: 1: /var/www/test_python_db.py: import: not found
/var/www/test_python_db.py: 2: /var/www/test_python_db.py: import: not found
/var/www/test_python_db.py: 3: /var/www/test_python_db.py: import: not found
/var/www/test_python_db.py: 6: /var/www/test_python_db.py: Syntax error: "(" unexpected

Bekomme dieses in der Konsole angezeigt.

Das PHP Script schreibt ja auch in die Datenbank wenn der Arduino nicht angeschlossen ist.
Muss an dem Arduino auch ein 10uF dran sein?

EDIT: Sorry, hatte sudo /var/www/test_python_db.py eingegeben
So hats geklappt python /var/www/test_python_db.py
Dankeee :slight_smile:

Wie ich verstanden habe, ist Qt sowas wie GUI Designer. Dazu nehme ich einmal jQuery Mobile und Dreamweaver.
Gäbe es irgendwelche Vorteile warum man Qt nutzen sollte/könnte?

Hi,
Qt ist nicht mit JQuery oder Dreamweaver zu vergleichen, da man keine Web Oberflächen baut, sondern komplette Anwendungen für Windows / Linux / Mac. Diese Anwendungen lassen sich selten für Web zwecke nutzen.

PHP schreibt in die Datenbank, da Python ja nicht weiß, ob gerade ein User auf dem Webserver irgendetwas gedruckt hat (Button).

Ich hab den Arduino nur per USB Verbunden. Wo willst du den 10µF den anschließen ?

Zwischen gnd und reset

Doppelpost.

Haben die Scripte bei dir denn nun funktioniert ?

Jep, klappt wunderbar. Würde nicht sagen dass man dazu richtig schlau sein muss, um alles zu installieren xD

Nur Autostart vom .py klappt nicht, bzw hab ich noch garnicht versucht.

Einfachste Möglichkeit

Eine recht universelle und sehr einfache Möglichkeit ist die Erstellung einer Datei im .config Ordner. Diese Möglichkeit habe ich bereits bei meinem Artikel über den VNC Server vorgestellt. Um beispielsweise ein eigenes Python Programm direkt nach dem Login oder Bootvorgang automatisch zu starten muss man folgendes machen:

einen neuen Ordner autostart under ~/.config erstellen
cd ~/.config
mkdir autostart
eine neue Datei mit der Endung .dektop erstellen
nano mypython.desktop
Konfiguration um ein Programm auszuführen

[Desktop Entry]
Name=MyPython
Exec=python mypython.py
Type=application
Nach einem Neustart sollte nun das angegebene Programm als erstes starten. Das Python Skript muss dabei im Homeverzeichnis des Benutzers liegen.

So hab ichs nun versucht, klappt aber mit dem Autostart nicht

So, endlich hats geklappt.

Die "Anleitung" Beitrag #1 hat nicht geklappt.
Der zweite Beitrag hats dann aufm Punkt gebracht.