Verarbeitung ankommender Daten Arduino GSM Shield 2

Guten Abend liebe Arduino Gemeinde,

Bisher habe habe ich zu den stillen Lesern im Forum gezählt, doch nun brauche ich eure Ratschläge. Bitte lasst es mich wissen, wenn ich meine Frage an der falschen Stelle gepostet habe.
Um eins vorne weg zu nehmen: Ich bin noch etwas grün hinter den Ohren, was das Programmieren anbelangt. :slight_smile:

Hardware:
-Arduino UNO
-GSM Shield 2
-2250mA Netzteil

Noch nicht verbaut:
-1x Relais
-1x RGB LED

Anforderungen:
-Das GSM-Modul soll per SMS:
-Speicher löschen Befehl: "#"
-Das Relais EIN/AUS schalten Befehl: "E"/ "0"
-Das Relais mit Zeitschaltfunktion EIN/AUS schalten Befehl: "Thhhmm"
-Statusmeldung an Absender zurückschicken, wenn angefordert Befehl: "S"

Jeweilige Statusanzeige per RGB LED

Bisherige Erfolge:
Nachricht senden sowie empfangen und mitsamt Absendernummer am Serial.Monitor ausgeben.

Problemstellung:

  1. Ich möchte das erste Zeichen der ankommenden Nachricht verwenden um mit der Funktion switch zwischen den oben genannten cases zu wählen, doch leider ist es mir bis anhin weder mit der Funktion atoi() noch mit anderen Methoden gelungen diese auszulesen. Könnt ihr mir einen Tipp geben?

2.Weiter möchte ich die fünf Stellen nach T also hhhmm der Nachricht "Thhhmm" verwenden um sie umzurechen und in der Zeitschaltfunktion case 'T' zu verwenden.

  1. Die Statusabfrage soll jederzeit, also auch während dem die Timerfunktion läuft angefordert werden können. Ist das mit meinem code, bzw. mit der Switch-Funktion überhaupt möglich?

Das ist mein code:

#include <GSM.h>
#define PINNUMBER "" //SIM-Karte ohne PIN > "" ; SIM-Karte mit PIN > "XXXX"

GSM gsmAccess;
GSM_SMS sms;

char senderNumber[20];               //Absendernummer
char data[8];                        //Speicher Befehlsnachricht
int timerValue = 0;                  //Timerzeit
int caseValue = 1;                   //Fallmerker 1:AUS und BEREIT ; 2:PERMANENT EIN ; 3:TIMERFUNKTION AKTIV
unsigned long remainingMillis = 0;   //Verbleibende Einschaltzeit Timer [Millisekunden]
unsigned long timerMillis = 0;     //Befohlene Timerzeit [Millisekunden]
const int relayPin = 8;              //RelaisPin
const int redLEDPin = 9;             //PWM~ Rot RGB
const int greenLEDPin = 10;          //PWM~ Grüne RGB
const int blueLEDPin = 11;           //PWM~ Blaue RGB


void setup() {
  for (int pinNumber = 8; pinNumber < 12; pinNumber++) {
    pinMode(pinNumber, OUTPUT);
    digitalWrite(pinNumber, LOW);
  }
  analogWrite(greenLEDPin, 255); //Zeichen Beginn Initialisierung
  Serial.begin(9600);
  while (!Serial) {
    ;
  }
  Serial.println("SMS Empf\344nger");

  boolean notConnected = true;
  while (notConnected) {
    if (gsmAccess.begin(PINNUMBER) == GSM_READY) {
      notConnected = false;
      digitalWrite(greenLEDPin, HIGH);
      analogWrite(blueLEDPin, 255); //Signal blau FixWitch -READY
    }
    else {
      Serial.println("Not connected");
      delay(1000);
    }
  }
  Serial.println("GSM initialisiert");
  Serial.println("SCHALTMODUL - READY");
}

void loop() {
  unsigned long currentMillis = millis(); //Zeit beim annkommen der Timerbefehls
  char rx_byte = 0; //Gelesene Nachricht wird hier gespeichert
  String rx_str = ""; //Gelesene Nachricht wird hierhin übergeben

  if (sms.available())   //Abfrage ob SMS verfügbar
  {
    Serial.println("Befehl erhalten von :");
    //Absendernummer erfassen
    sms.remoteNumber(senderNumber, 20);
    // Beispiel : +0791234567
    //Serial.println(remoteNumber);
    Serial.println(senderNumber);
    if (sms.peek() == '#') // Nachrichten die nur "#" enthalten, bewirken die Löschung des Speichers
    {
      Serial.println("\nSMS-Speicher gelöscht\n");

      sms.flush();      // Modem-Speicher löschen
    }

    while (rx_byte = sms.read())
    {
      rx_str += rx_byte;
    }
    int n;
    if (rx_str.startsWith("0")) {
      n = "0";
    }
    else if (rx_str.startsWith("E")) {
      n = "E";
    }
    else if (rx_str.startsWith("T")) {
      n = "T";
    }
    else if (rx_str.startsWith("T")) {
      n = "S";
    }
    switch (n)
    {
      case '0':
        caseValue = 1;
        digitalWrite(8, LOW);
        analogWrite(redLEDPin, 255);
        Serial.println("\nFixWitch STOP\n");
        delay(3000);
        break;

      case 'E':
        caseValue = 2;
        if (rx_byte == 'E')
          digitalWrite(8, HIGH);

        analogWrite(greenLEDPin, 255);
        Serial.println("\nRELAIS PERMANENT EIN\n");
        break;

      case 'T':
        caseValue = 3;
        Serial.println("\nRELAIS TIMERFUNKTION\n");
        currentMillis = millis();
        remainingMillis = currentMillis + timerMillis;
        boolean timeLeft = true;
        while (timeLeft) {
          digitalWrite(8, HIGH);
          analogWrite(blueLEDPin, 255);
          analogWrite(greenLEDPin, 255);
          if (currentMillis < remainingMillis) {
            timeLeft = true;
          }
          else {
            timeLeft = false;
          }
          Serial.println("\nTimer abgelaufen!\n");
          break;

        case 'S':
          Serial.println(data[0]);
          sms.beginSMS(senderNumber);
          sms.print("SCHALTMODUL:\nSTATUS:");
          if (caseValue == 1) {
            sms.print("\nAUS und BEREIT\n");
          }
          else if ( caseValue == 2) {
            sms.print("\nPERMANENT EIN\n");
          }
          else {
            sms.print("\nTIMER AKTIV\n");

          }
          sms.endSMS();
          Serial.println("\nStatusnachricht versendet!\n");
          break;
        default:
          sms.beginSMS(senderNumber);
          sms.print("Falscher Befehl");
          sms.print("0 = AUS");
          sms.print("E = EIN");
          sms.print("Thhhmm = TIMER");
          sms.print("S = STATUS");
          sms.endSMS();
          break;
        }
    }
    Serial.print(rx_str);
    sms.flush();
    rx_str = "";
    delay(1000);
  }
}  //Finale Klammer void loop().
case 'T':
        caseValue = 3;
        Serial.println("\nRELAIS TIMERFUNKTION\n");
        currentMillis = millis();
        remainingMillis = currentMillis + timerMillis;
        boolean timeLeft = true;
        while (timeLeft) {
          digitalWrite(8, HIGH);
          analogWrite(blueLEDPin, 255);
          analogWrite(greenLEDPin, 255);
          if (currentMillis < remainingMillis) {
            timeLeft = true;
          }
          else {
            timeLeft = false;
          }
          Serial.println("\nTimer abgelaufen!\n");
          break;

Bei folgender Zeile erhalte ich momentan eine Fehlermeldung:

        boolean timeLeft = true;

Fehlermeldung:

receive_SMS_switch_case:108: error: crosses initialization of 'boolean timeLeft'

exit status 1
crosses initialization of 'boolean timeLeft'

Ich bedanke mich bereits jetzt für eure Vorschläge und eure Zeit!

  1. Nimm nicht die Klasse String, sondern

char rx_str[10]; // die maximal erwartete Länge hier 10
dann ist es

if (rx_str[0] == 'T') 

// oder

 switch rx_str[0] {
  case 'T':
}

3. ziehe das boolean timeLeft = false; mal an den Anfang von loop.
und schreibe in case 'T':
   timeLeft = true;

2. Hier muss man etwas mehr ausholen. Schreibe immer 2 Byte in ein char dummy[2] und setze dummy[2] = '\0'.
Dann kanst Du die Teile in Zahlen umwandeln.

Edit. Dazu kannst Du Dir auch mal [url=https://www.wikinger-tommy.de/arduino/tut_zeichenketten.html]Zeichenketten in C[/url] anschauen.

Gruß Tommy

Hallo Tommy,

Danke für deine ausführlichen Tipps. Ich habe deinen Link verfolgt und mich durchgelesen. Bis zur Zählweise von Arrays des Typs char und dass sie mit einer "\0" abgeschlossen werden müssen konnte ich folgen. Auch die Tatsache, dass genügend Platz für die ankommenden Daten geschaffen werden muss leuchtet mir ein. Mit Zeigern oder ähnlichen habe ich mich jedoch noch nie befasst.

Ich habe deine Tipps wie folgt versucht umzusetzen:

-char rx_str[10] anstelle von String rx_str = ""
-boolean timeLeft = true von case 'T' zum Anfang des loops

void loop() {
  boolean timeLeft = true;
  unsigned long currentMillis = millis(); //Zeit beim annkommen der Timerbefehls
  char rx_byte = 0; //Gelesene Nachricht wird hier gespeichert
 [b] char rx_str[10];[/b] //Gelesene Nachricht wird hierhin übergeben

-switch (rx_str[0]) definiert
-timeLeft = true in case 'T'

 case 'T':
caseValue = 3;
 Serial.println("\nRELAIS TIMERFUNKTION\n");
 currentMillis = millis();
 remainingMillis = currentMillis + timerMillis;
[b] timeLeft = true;[/b]

Nun erhalte ich die Fehlermeldung:

receive_SMS_switch_case:69: error: incompatible types in assignment of 'int' to 'char [10]'

     while (rx_str = sms.read())

                   ^

receive_SMS_switch_case:71: error: incompatible types in assignment of 'char' to 'char [10]'

       rx_str += rx_byte;

              ^

exit status 1
incompatible types in assignment of 'int' to 'char [10]'

Die Funktion sms.read() kann seine Daten nicht in ein char packen, aber wieso?

char dummy[2] definiert, da sehe ich jedoch noch gar nicht durch.

Was meinst du mit 2 Byte auf einmal schreiben?

#include <GSM.h>
#define PINNUMBER "" //SIM-Karte ohne PIN > "" ; SIM-Karte mit PIN > "XXXX"

GSM gsmAccess;
GSM_SMS sms;

char senderNumber[20];               //Absendernummer
char data[8];                        //Speicher Befehlsnachricht
[b]char dummy[2]; [/b]                       //
int timerValue = 0;                  //Timerzeit
int caseValue = 1;                   //Fallmerker 1:AUS und BEREIT ; 2:PERMANENT EIN ; 3:TIMERFUNKTION AKTIV
unsigned long remainingMillis = 0;   //Verbleibende Einschaltzeit Timer [Millisekunden]
unsigned long timerMillis = 0;     //Befohlene Timerzeit [Millisekunden]
const int relayPin = 8;              //RelaisPin
const int redLEDPin = 9;             //PWM~ Rot RGB
const int greenLEDPin = 10;          //PWM~ Grüne RGB
const int blueLEDPin = 11;           //PWM~ Blaue RGB


void setup() {

gesamter code:

#include <GSM.h>
#define PINNUMBER "" //SIM-Karte ohne PIN > "" ; SIM-Karte mit PIN > "XXXX"

GSM gsmAccess;
GSM_SMS sms;

char senderNumber[20];               //Absendernummer
char data[8];                        //Speicher Befehlsnachricht
char dummy[2];                        //
int timerValue = 0;                  //Timerzeit
int caseValue = 1;                   //Fallmerker 1:AUS und BEREIT ; 2:PERMANENT EIN ; 3:TIMERFUNKTION AKTIV
unsigned long remainingMillis = 0;   //Verbleibende Einschaltzeit Timer [Millisekunden]
unsigned long timerMillis = 0;     //Befohlene Timerzeit [Millisekunden]
const int relayPin = 8;              //RelaisPin
const int redLEDPin = 9;             //PWM~ Rot RGB
const int greenLEDPin = 10;          //PWM~ Grüne RGB
const int blueLEDPin = 11;           //PWM~ Blaue RGB


void setup() {
  for (int pinNumber = 8; pinNumber < 12; pinNumber++) {
    pinMode(pinNumber, OUTPUT);
    digitalWrite(pinNumber, LOW);
  }
  analogWrite(greenLEDPin, 255); //Zeichen Beginn Initialisierung
  Serial.begin(9600);
  while (!Serial) {
    ;
  }
  Serial.println("SMS Empf\344nger");

  boolean notConnected = true;
  while (notConnected) {
    if (gsmAccess.begin(PINNUMBER) == GSM_READY) {
      notConnected = false;
      digitalWrite(greenLEDPin, HIGH);
      analogWrite(blueLEDPin, 255); //Signal blau FixWitch -READY
    }
    else {
      Serial.println("Not connected");
      delay(1000);
    }
  }
  Serial.println("GSM initialisiert");
  Serial.println("SCHALTMODUL - READY");
}

void loop() {
  boolean timeLeft = true;
  unsigned long currentMillis = millis(); //Zeit beim annkommen der Timerbefehls
  char rx_byte = 0; //Gelesene Nachricht wird hier gespeichert
  char rx_str[10]; //Gelesene Nachricht wird hierhin übergeben

  if (sms.available())   //Abfrage ob SMS verfügbar
  {
    Serial.println("Befehl erhalten von :");
    //Absendernummer erfassen
    sms.remoteNumber(senderNumber, 20);
    // Beispiel : +0791234567
    //Serial.println(remoteNumber);
    Serial.println(senderNumber);
    if (sms.peek() == '#') // Nachrichten die nur "#" enthalten, bewirken die Löschung des Speichers
    {
      Serial.println("\nSMS-Speicher gelöscht\n");

      sms.flush();      // Modem-Speicher löschen
    }

    while (rx_str = sms.read())
    {
      rx_str += rx_byte;
    }
    switch (rx_str[0])
    {
      case '0':
        caseValue = 1;
        digitalWrite(8, LOW);
        analogWrite(redLEDPin, 255);
        Serial.println("\nFixWitch STOP\n");
        delay(3000);
        break;

      case 'E':
        caseValue = 2;
        if (rx_byte == 'E')
        digitalWrite(8, HIGH);
        analogWrite(greenLEDPin, 255);
        Serial.println("\nRELAIS PERMANENT EIN\n");
        break;

      case 'T':
        caseValue = 3;
        Serial.println("\nRELAIS TIMERFUNKTION\n");
        currentMillis = millis();
        remainingMillis = currentMillis + timerMillis;
        timeLeft = true;
        while (timeLeft) {
          digitalWrite(8, HIGH);
          analogWrite(blueLEDPin, 255);
          analogWrite(greenLEDPin, 255);
          if (currentMillis < remainingMillis) {
            timeLeft = true;
          }
          else {
            timeLeft = false;
          }
          Serial.println("\nTimer abgelaufen!\n");
          break;

        case 'S':
          Serial.println(data[0]);
          sms.beginSMS(senderNumber);
          sms.print("SCHALTMODUL:\nSTATUS:");
          if (caseValue == 1) {
            sms.print("\nAUS und BEREIT\n");
          }
          else if ( caseValue == 2) {
            sms.print("\nPERMANENT EIN\n");
          }
          else {
            sms.print("\nTIMER AKTIV\n");

          }
          sms.endSMS();
          Serial.println("\nStatusnachricht versendet!\n");
          break;
        default:
          sms.beginSMS(senderNumber);
          sms.print("Falscher Befehl");
          sms.print("0 = AUS");
          sms.print("E = EIN");
          sms.print("Thhhmm = TIMER");
          sms.print("S = STATUS");
          sms.endSMS();
          break;
        }
    }
    Serial.print(rx_str);
    sms.flush();
    rx_str = "";
    delay(1000);
  }
}  //Finale Klammer void loop().

Bei folgender Zeile erhalte ich momentan eine Fehlermeldung:

Völlig zu Recht. Du kannst in einem case keine Variablen deklarieren. Dazu musst du einen Code Block mit { } anlegen

rx_str += rx_byte;

Was soll das? rx_str ist ein Array. Wie willst du eine Integer-Variable addieren?

Hallo Serenifly,

Die Variable rx_str[10] wird bereits weiter oben deklariert. Ich möchte an dieser Stelle lediglich das erste Zeichen der ankommenden SMS abfragen, deshalb doch auch die [0]. oder liege ich da komplett daneben?

Die Daten die die Funktion sms.read() ausspuckt sollen "irgendwie" mit Buchstaben oder Zahlen verglichen werden. Wie stelle ich das an?

  1. Nimm nicht die Klasse String, sondern

char rx_str[10]; // die maximal erwartete Länge hier 10
dann ist es :

if (rx_str[0] == 'T')

// oder

switch rx_str[0] {
case 'T':
}

Ich möchte an dieser Stelle lediglich das erste Zeichen der ankommenden SMS abfragen. ... Die Daten die die Funktion sms.read() ausspuckt sollen "irgendwie" mit Buchstaben oder Zahlen verglichen werden. Wie stelle ich das an?

Genau so :

if (rx_str[0] == 'T')

// oder

switch rx_str[0] {
case 'T':

receive_SMS_switch_case:71: error: incompatible types in assignment of 'char' to 'char [10]'
rx_str += rx_byte;
^

Ist eine dumme Angewohnheit, zu denken + wäre ein sinnvoller Operator, um einen Buchstaben in ein Array zu laden.

Da du nur wenig zeigst, kriegst du auch nur spärliche Tips:

char rx_str[10];  // Puffer
byte pos=0;  // Schreibzeiger
...
while (sms.available() )  {
   if (pos < sizeof(rx_str) rx_str[pos++] = sms.read(); // 1 Zeichen lesen, Lesezeiger erhöhen
}
if (pos < sizeof(rx_str)) rx_str[pos] = 0; // Endekennung für Text

Bin jetzt zu faul, rauszukriegen ob GSM_SMS available() kennt, ob dann immer alles komplett da ist, und warum du denkst, 10 Buchstaben reichen dafür.
Je nach dem , wo/wie pos definiert ist, musst du das auch passend wieder auf 0 zurücksetzen.