[Arduino] MySQL Datenabfrage und Datenempfang in gleichem Sketch

Moin, Moin!

Ein Freund und ich versuchen aktuell unser eigenes Smart Home-System zum laufen zu bringen. Für diesen Zweck haben wir bereits ein eigenes User-Interface in Form einer Web-Applikation entworfen. Verschiedene Arduino-Sensoren (ESP8266 Node-MCU-12 Module) kommunizieren bereits mit einer Datenbank, die von dem UI ausgelesen wird.

Allerdings haben wir noch ein grundsätzliches Problem: Wir verwenden einen Magnetsensor (switchReed) als Türsensor, um zu überprüfen, ob die Haustür geöffnet oder geschlossen ist. Bei dem jeweiligen Zustand wird entweder eine "1" (geöffnet) oder eine "0" (geschlossen) in die Datenbank geschrieben und die Web-Oberfläche liest die Datenbank aus, um dann das richtige Icon anzuzeigen. Dieser Vorgang funktioniert bereits. Zusätzlich soll nun ein Buzzer über die Web-Oberfläche gesteuert werden können (Alarmfunktion ein- und ausschalten). Die Buttons für das Ein- und Ausschalten der Alarmanlage schreiben ebenfalls "1" (aktiv) und "0" (inaktiv) in eine separate Datenbank. Nun soll der Arduino-Sketch neben der Meldung (Türstatus offen/ geschlossen) eine Abfrage starten, ob der Alarm aktiv oder inaktiv ist. Sofern dieser aktiv ist, muss der Buzzer einen Ton erklingen lassen, sobald die Tür geöffnet wird.

Im Folgenden nun also unter Sketch. Wir wissen absolut nicht weiter und wenn uns jemand einen Weg aufzeigen kann, wie wir das Problem beheben können, wären wir dankbar:

Der Code folgt im nächsten Post!

//MySQL
#include <MySQL_Connection.h> // Einbindung Bibliothek; Verbindung zum MySQL-Server
#include <MySQL_Cursor.h>     // Einbindung Bibliothek; Schreiben in die MySQL-Datenbank
#include <ESP8266WiFi.h>      // Einbindung Bibliothek; Verwendung des Arduino ESP8266
#include <WiFiClient.h>       // Einbindung Bibliothek; Verbindung zum WLAN

const int switchReed=13;            // Deklarierung der Variable switchReed; Festlegung des PINS 12
const int buzzer = 12;

//WiFi + MySQL
WiFiServer server(301);     // Initalisierung eines WiFi-Servers mit dem entsprechenden Port
const char *ssid =  "UNSER WLAN";    // Name des WLAN's, mit dem sich der Arduino verbinden soll
const char *pass =  "UNSER PASSWORT";     // Passwort des WLAN's, mit dem verbunden werden soll
const char* host = "";        // Offizieller Name des Hosts 
byte mac[6];                  // Mac-Adresse für den WiFi-Shield
WiFiClient client;            // Erstellung eines Clients zur Verbindung mit einer spezifizierten IP-Adresse
MySQL_Connection conn((Client *)&client);     // Erstellung eines Clients zur Verbindung mit einem MySQL-Server

char query[] = "SELECT Spalte FROM Datenbankname.Datenbanktabelle";
char INSERT_SQL[] = "INSERT INTO Datenbankname.Datenbanktabelle(Spalte) VALUES (%d)";  // Anweisung, dass erhobene Daten in die entsprechende Datenbank geschrieben werden soll

IPAddress server_addr(XXX, XXX, XXX, XXX);          // IP-Adresse des MySQL-Servers
char user[] = "UNSER BENUTZER";           // Benutzername für die MySQL-Datenbank
char password[] = "UNSER BENUTZER_PASSWORT";       // Passwort für die MySQL-Datenbank

void setup() {     // Void Setup; Initialisierung einmaliger Vorgänge

  Serial.begin(9600);           // Initialisierung der seriellen Schnittstelle
  pinMode(switchReed, INPUT);   // Auslesen des Magnetsensors
  pinMode(buzzer, OUTPUT); 
  
  //WiFi + MySQL
  Serial.begin(9600);    // Initialisierung der seriellen Schnittstelle
  delay(10);             // Unterbrechung (10 Millisekunden)

  Serial.println("Connecting to ");       // Serielle Textausgabe "Connecting to" in neuer Zeile
  Serial.println(ssid);                   // Serielle Textausgabe des Netzwerk-Names in neuer Zeile

  WiFi.begin(ssid, pass);                      // Initialisierung der Netzwerk-Einstellungen aus Bibliothek; Abgleich des Netzwerknames und des Passworts
  while (WiFi.status() != WL_CONNECTED) {      // While-Schleife; Anweisung etwas zu tun, solange die Verbindung zum Netzwerk nicht hergestellt ist
      delay(500);                              // Unterbrechung (500 Millisekunden)
      Serial.print(".");                       // Serielle Textausgabe "."
   }
  Serial.println("");                          // Serielle Textausgabe " " in neuer Zeile
  Serial.println("WiFi connected");            // Serielle Textausgabe "Wifi Connected" in neuer Zeile

  WiFi.macAddress(mac);           // Abfrage der MAC-Adresse für den WiFi-Shield des EPS8266
  Serial.print("MAC: ");          // Serielle Textausgabe "MAC: "
  Serial.print(mac[5],HEX);       // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 5-Byte-Array
  Serial.print(":");              // Serielle Textausgabe ":"
  Serial.print(mac[4],HEX);       // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 4-Byte-Array
  Serial.print(":");              // Serielle Textausgabe ":"
  Serial.print(mac[3],HEX);       // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 3-Byte-Array
  Serial.print(":");              // Serielle Textausgabe ":"
  Serial.print(mac[2],HEX);       // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 2-Byte-Array
  Serial.print(":");              // Serielle Textausgabe ":"
  Serial.print(mac[1],HEX);       // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 1-Byte-Array
  Serial.print(":");              // Serielle Textausgabe ":"
  Serial.println(mac[0],HEX);     // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 0-Byte-Array in neuer Zeile
  Serial.println("");             // Serielle Textausgabe " " in neuer Zeile
  Serial.print("Assigned IP: ");  // Serielle Textausgabe "Assigned IP: "
  Serial.print(WiFi.localIP());   // Serielle Textausgabe der für die dem WiFi-Shield zugewiesene IP-Adresse
  Serial.println("");             // Serielle Textausgabe " " in neuer Zeile

  
}


void loop() {
 
 row_values *row = NULL;
  long head_count = 0;

  delay(1000);

//---------------------------------------------------------SENDING DOOR STATUS------------------------------------------------------------------

  if (conn.connect(server_addr, 3306, user, password)) {     // While-Schleife; Abgleich der MySQL-Server-Adresse, des Server-Ports, des Benutzernamens und des Benutzer-Passworts  
    
  // Initiate the query class instance
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);

    if (digitalRead(switchReed)==HIGH){       // if-Schleife; Anweisung etwas zu tun, wenn Daten vom Magnet-Sensot empfangen werden
    Serial.println("Your Door is Closed");  // Serielle Textausgabe "Your Door is Closed" in neuer Zeile
    sprintf(query, INSERT_SQL, 0);          // Schreiben des Wertes "0" in die deklarierte MySQL-Datenbank
  }
  else {                                    // else-Anweisung; alternative Anweisung, wenn die if-Schleife nicht erfüllt ist
    Serial.println("Your Door is Open");    // Serielle Textausgabe "Your Door is Open" in neuer Zeile 
    sprintf(query, INSERT_SQL, 1);          // Schreiben des Wertes "1" in die deklarierte MySQL-Datenbank
 }
  delay(100);

    delete cur_mem;
  // Note: since there are no results, we do not need to read any data
  // Deleting the cursor also frees up memory used

  Serial.println("Data recorded.");
}

else {
  Serial.println("Connection failed.");
}
  //--------------------------------------------------------READING BUZZER STATUS----------------------------------------------------------------------

Serial.println("Hier stoppt der Sketch?!"); 
 
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
  // Execute the query
  // cur_mem->execute(query);
  // Fetch the columns (required) but we don't use them.
  column_names *columns = cur_mem->get_columns();

  // Read the row (we are only expecting the one)
  do {
    row = cur_mem->get_next_row();
    if (row != NULL) {
      head_count = atol(row->values[0]);
    }
  } while (row != NULL);
  // Deleting the cursor also frees up memory used

  delay(500);

  if (head_count == 1 && digitalRead(switchReed)==LOW)         // if-Schleife; Anweisung etwas zu tun, wenn der auslesene Wert größer als die Variable sensorThres ist
  {
    Serial.println("Der Buzzer ist !!!>AKTIV<!!!");     // Serielle Textausgabe "Achtung! Feueralarm!" in neuer Zeile
    tone(buzzer, 1000);                     // Send 1KHz sound signal...
    delay(1);                            // ...for 1 sec
    tone(buzzer, 1000);                     // Send 1KHz sound signal...
    delay(1);                            // ...for 1sec
  }
  else
  {
    Serial.println("Der Buzzer ist !!!>INAKTIV<!!!");// Serielle Textausgabe "Keine Rauch- und Feuermeldungen vorhanden" in neuer Zeile                 
    noTone(buzzer);                         // Stop sound...
  }
  delay(100);                               // Unterbrechung (5 Millisekunden)

  cur_mem->execute(query);

  delete cur_mem;
  
  conn.close();

  delay (10000);

}

Unser generelles Problem betrifft den void loop () ... dieser startet erfolgreich, indem er den Magnetsensor (switchReed) ausliest und den Status an die Datenbank weitergibt. Allerdings stoppt der
Sketch nach diesem Vorgang.

Woran kann es liegen ????

Vielen Dank im Voraus!!!!!!!

Viele Grüße,
Quooch

Wie lange dauert ein loop() Durchlauf bei euch?
Passt das zu der AlarmPiepser-Funktion ? Wenn nicht, solltet ihr die delay(10000); u.ä. durch eine nicht blockierende Zustandsführung ersetzen.

Wenn ich Kommentare wie

  Serial.println("Hier stoppt der Sketch?!");

sehe, wundere ich mich etwas.

Auch

 // Deleting the cursor also frees up memory used

ohne entsprechenden Code macht mich stutzig, ob man das nicht erst reparieren sollte, bevor man weitere Funktionen anfügt. ( Edit: Ah, weiter hinten schwirrt ein delete rum )

Also: bitte erstmal aufräumen und Kommentare korrigieren,
dann die eigentliche Frage dieses Threads
"MySQL Datenabfrage und Datenempfang in gleichem Sketch"
durch eine einfache TestLED realisieren und schauen ob die vorhandenen Verzögerungen so erträglich sind.

Ich würde eher einmal die Connection öffnen, lesen (SELECT) nur bei Bedarf ein schreib (INSERT) durchführen und wieder schliessen.

Wie lange soll es übrigens piepsen? Bis Tür zu, Freigabe weg, Datenbank-Freigabe weg, aber mindestens mal 1 sec lang?

Daraus ergibt sich schonmal ein Anhalts-Wert für das max. erlaubte delay in loop() :wink:

Hallo michael_X,

vielen Dank für die schnelle Antwort!

Wie lange dauert ein loop() Durchlauf bei euch?

Das würde ich Dir gerne beantworten, aber selbst nach einigen Minuten warten, reagiert der Sketch nicht mehr ... also kann ich es leider nicht sagen.

Also: bitte erstmal aufräumen und Kommentare korrigieren,
dann die eigentliche Frage dieses Threads
"MySQL Datenabfrage und Datenempfang in gleichem Sketch"

durch eine einfache TestLED realisieren und schauen ob die vorhandenen Verzögerungen so erträglich sind.

Ich würde eher einmal die Connection öffnen, lesen (SELECT) nur bei Bedarf ein schreib (INSERT) durchführen und wieder schliessen.

Wir haben eine Abfrage unserer Datenbank bereits realisiert. In diesem Fall funktioniert es problemlos. Wir können mit Hilfe unserer Benutzeroberfläche eine Lampe ein- und ausschalten. Der Anwendungsfall ist ähnlich dem der Alarmanlage: Wenn wir den Einschaltbutton für das Licht betätigen, wird eine "1" an die Datenbank gesendet, beim Ausschalten eine "0". Der Arduino-Sketch fragt ab, ob eine "1" in der Datenbank
gespeichert wurde. Wenn ja, wird die Lampe eingeschaltet.

Wie lange soll es übrigens piepsen? Bis Tür zu, Freigabe weg, Datenbank-Freigabe weg, aber mindestens mal 1 sec lang?

Daraus ergibt sich schonmal ein Anhalts-Wert für das max. erlaubte delay in loop() :wink:

Insgesamt soll es solange piepsen, bis die Tür wieder geschlossen wird (bei aktivierter Alarmschaltung) ... wenn die Alarmschaltung inaktiv ist, soll der Buzzer natürlich weder bei geöffneter noch bei geschlossener
Tür piepsen.

Quooch:

  WiFi.macAddress(mac);           // Abfrage der MAC-Adresse für den WiFi-Shield des EPS8266

Serial.print("MAC: ");          // Serielle Textausgabe "MAC: "
 Serial.print(mac[5],HEX);       // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 5-Byte-Array
 Serial.print(":");              // Serielle Textausgabe ":"
 Serial.print(mac[4],HEX);       // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 4-Byte-Array
 Serial.print(":");              // Serielle Textausgabe ":"
 Serial.print(mac[3],HEX);       // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 3-Byte-Array
 Serial.print(":");              // Serielle Textausgabe ":"
 Serial.print(mac[2],HEX);       // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 2-Byte-Array
 Serial.print(":");              // Serielle Textausgabe ":"
 Serial.print(mac[1],HEX);       // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 1-Byte-Array
 Serial.print(":");              // Serielle Textausgabe ":"
 Serial.println(mac[0],HEX);     // Serielle Textausgabe der MAC-Adresse; Speicherung in einem 0-Byte-Array

Welchen Sinn macht es die MacAdresse gespiegelt auszugeben?

Für was braucht man das?

Gruß Fips

Welchen Sinn macht es die MacAdresse gespiegelt auszugeben?

Für was braucht man das?

Gruß Fips

Vielen Dank für deine Antwort. Grundsätzlich hast du recht, dass es nicht benötigt wird. Allerdings
ist der Code in dieser Form in unserer Quelle angegeben und wir haben den Sketch nicht weiter in dieser Hinsicht bearbeitet.

Deine Anmerkung haben wir umgesetzt und einen Code gebastelt, allerdings funktioniert er noch nicht:

//MySQL
#include <MySQL_Connection.h> // Einbindung Bibliothek; Verbindung zum MySQL-Server
#include <MySQL_Cursor.h>     // Einbindung Bibliothek; Schreiben in die MySQL-Datenbank
#include <ESP8266WiFi.h>      // Einbindung Bibliothek; Verwendung des Arduino ESP8266
#include <WiFiClient.h>       // Einbindung Bibliothek; Verbindung zum WLAN

int buzzer = 12;
const int switchReed=13;

//WiFi + MySQL
WiFiServer server(301);     // Initalisierung eines WiFi-Servers mit dem entsprechenden Port
const char *ssid =  "UNSER WLAN";    // Name des WLAN's, mit dem sich der Arduino verbinden soll
const char *pass =  "UNSER PASSWORT";     // Passwort des WLAN's, mit dem verbunden werden soll
const char* host = "";        // Offizieller Name des Hosts 
byte mac[6];                  // Mac-Adresse für den WiFi-Shield
WiFiClient client;            // Erstellung eines Clients zur Verbindung mit einer spezifizierten IP-Adresse
MySQL_Connection conn((Client *)&client);     // Erstellung eines Clients zur Verbindung mit einem MySQL-Server

IPAddress server_addr(XXX, XX, XX, XX);          // IP-Adresse des MySQL-Servers
char user[] = "BENUTZER";           // Benutzername für die MySQL-Datenbank
char password[] = "PASSWORT";       // Passwort für die MySQL-Datenbank

// Sample query
char query[] = "SELECT light FROM k71273_esp.02_fl_bulb";
char INSERT_SQL[] = "INSERT INTO k71273_esp.02_fl_door(status) VALUES (%d)";  // Anweisung, dass erhobene Daten in die entsprechende Datenbank geschrieben werden soll

void setup() {     // Void Setup; Initialisierung einmaliger Vorgänge

  pinMode(buzzer, OUTPUT); 
  
  //WiFi + MySQL
  Serial.begin(9600);    // Initialisierung der seriellen Schnittstelle
  delay(10);             // Unterbrechung (10 Millisekunden)

  Serial.println("Connecting to ");       // Serielle Textausgabe "Connecting to" in neuer Zeile
  Serial.println(ssid);                   // Serielle Textausgabe des Netzwerk-Names in neuer Zeile

  WiFi.begin(ssid, pass);                      // Initialisierung der Netzwerk-Einstellungen aus Bibliothek; Abgleich des Netzwerknames und des Passworts
  while (WiFi.status() != WL_CONNECTED) {      // While-Schleife; Anweisung etwas zu tun, solange die Verbindung zum Netzwerk nicht hergestellt ist
      delay(500);                              // Unterbrechung (500 Millisekunden)
      Serial.print(".");                       // Serielle Textausgabe "."
   }
  Serial.println("");                          // Serielle Textausgabe " " in neuer Zeile
  Serial.println("WiFi connected");            // Serielle Textausgabe "Wifi Connected" in neuer Zeile

  WiFi.macAddress(mac);           // Abfrage der MAC-Adresse für den WiFi-Shield des EPS8266

  Serial.println("Connecting to database");        // Serielle Textausgabe "Connecting to database" in neuer Zeile

  while (conn.connect(server_addr, 3306, user, password) != true) {     // While-Schleife; Abgleich der MySQL-Server-Adresse, des Server-Ports, des Benutzernamens und des Benutzer-Passworts  
      delay(5);                 // Unterbrechung (5 Millisekunden)
      Serial.print ( "." );     // Serielle Textausgabe "."
  }

  Serial.println("");           // Serielle Textausgabe " " in neuer Zeile
  Serial.println("Connected to SQL Server!");  // Serielle Textausgabe "Connected to SQL Server!" in neuer Zeile; Mitteilung erfolgreiche Verbindung

}

void BuzzerOnOff() {

 MySQL_Cursor cur = MySQL_Cursor(&conn);
 
 row_values *row = NULL;
  long head_count = 0;

  delay(1000);

  Serial.println("1) Demonstrating using a cursor dynamically allocated.");
  // Initiate the query class instance
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
  // Execute the query
  cur_mem->execute(query);
  // Fetch the columns (required) but we don't use them.
  column_names *columns = cur_mem->get_columns();

  // Read the row (we are only expecting the one)
  do {
    row = cur_mem->get_next_row();
    if (row != NULL) {
      head_count = atol(row->values[0]);
    }
  } while (row != NULL);
  // Deleting the cursor also frees up memory used
  delete cur_mem;

  // Show the result
  // Serial.print("  NYC pop = ");
  // Serial.println(head_count);

  delay(500);

  if (head_count == 1)         // if-Schleife; Anweisung etwas zu tun, wenn der auslesene Wert größer als die Variable sensorThres ist
  {
    Serial.println("Der Alarm ist !>aktiv<!");     // Serielle Textausgabe "Achtung! Feueralarm!" in neuer Zeile
    tone(buzzer, 1000);
  }
  else
  {
    Serial.println("Der Alarm ist !>inaktiv<!");   // Serielle Textausgabe "Keine Rauch- und Feuermeldungen vorhanden" in neuer Zeile                 
    noTone(buzzer);
  }

}

void loop() {                    // Ausführung des eigentlichen Programms
  if (digitalRead(switchReed)==LOW){       // if-Schleife; Anweisung etwas zu tun, wenn Daten vom Magnet-Sensot empfangen werden
    Serial.println("Your Door is Open");   // Serielle Textausgabe "Your Door is Closed" in neuer Zeile
    BuzzerOnOff();                                  // Ausführen der Anweisung "BuzzerOnOff"
    sprintf(query, INSERT_SQL, 1);          // Schreiben des Wertes "0" in die deklarierte MySQL-Datenbank
  }
  else {                                    // else-Anweisung; alternative Anweisung, wenn die if-Schleife nicht erfüllt ist
    Serial.println("Your Door is Closed");    // Serielle Textausgabe "Your Door is Open" in neuer Zeile 
    sprintf(query, INSERT_SQL, 0);          // Schreiben des Wertes "1" in die deklarierte MySQL-Datenbank
  }
  delay(100);                               // Unterbrechung (5 Millisekunden)

  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);

  cur_mem->execute(query);

  delete cur_mem;
}