SMS senden und Daten in die Arduino Cloud speichern

Hallo,

ich habe einen Arduino MKR GSM 1400 mit dem ich Daten in die ArduinoCloud senden möchte und bei Bedarf auch eine SMS schicken will, um auf irgendeinen Zustand besonders hinzuweisen.

Zur Unterstützung der Spannungsversorgung habe ich einen Lithium-Akku am Arduino angeschlossen.

Mit dem Programm möchte ich einen AnalogWert in die Arduino Cloud speichern.

Ich simuliere die Werte mir einem Poti, später soll da ein analoger Drucksensor dran kommen.

Jetzt möchte ich es so erweitern, das ich eine SMS versende, wenn der Wert außerhalb der vorgegebenen Grenze liegt. (2V im Beispiel)

Das Programm läuft bis zu dem Punkt wo eine SMS gesendet werden soll. Bei der Funktion „sms.endSMS();“ scheint der Controller einen Reset auszulösen/abzustürzen (irgendsowas) - die USB Verbindung bricht kurz ab und wird wieder her gestellt. Das letzte was ich im SerialMonitor sehe ist die "2" die nach "sms.print(txtMsg)" geschrieben wird gefolgt von den 2s delay.

Wenn ich über

#define DoArduinoCloud

oder

#define DoSMS

die jeweiligen Programmteile ausblende funktioniert der jeweils aktive Teil ohne Probleme, ich kann beliebig viele SMS nacheinander versenden, oder über lange Zeit Daten in die ArduinoCloud senden.

Meine Frage ist also: Wie schaffe ich es beide Funktionen in einem Script zu vereinen?
Ich denke es wird notwendig sein das GSM Modul irgendwie neu zu konfigurieren.

Dann bleibt noch die Frage wie ich nach der SMS wieder zur ArduinoCloud verbinde.
Reicht es einfach "ArduinoCloud.begin(ArduinoIoTPreferredConnection)" auszuführen, oder muss da noch etwas mehr für passieren?

Beste Grüße,

Martin



/* 
  Sketch generated by the Arduino IoT Cloud Thing "Untitled 2"
  https://create.arduino.cc/cloud/things/98aaafea-ad49-46f3-a153-e75f419b8b24 

  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  float temperatur;
  int wert;
  float druck;

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/


#include <MKRGSM.h>           //GSM Library to support SMS
#include <LCD_I2C.h>          //Library for LCD display control
#include "thingProperties.h"

#define LED_ON_BOARD 6          //LED PIN on Arduino Board
#define LED_RED 0               //off board LED 
#define PressureSensor A1       //Analogeingang für Drucksensor

//#define DoArduinoCloud
#define DoSMS

const char SMSPIN[] = "0000";
GSM gsmAccess;
GSM_SMS sms;

LCD_I2C lcd(0x3F);        // Address PCF8574 display


int           iAdcRawPressure = 0;
float         fPressureVoltage = 0;
unsigned long ulLastMillis = 0;

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  delay(1500); 

// analoge setup:
  analogReference(AR_DEFAULT);  //3.3V internal reference


//Connect to Arduino IoT Cloud
  initProperties();

#ifdef DoArduinoCloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  setDebugMessageLevel(3);
  ArduinoCloud.printDebugInfo();
#endif

 
  lcd.begin();
  lcd.backlight();
  lcd.clear();

}

void loop() {
#ifdef DoArduinoCloud
  ArduinoCloud.update();
#endif

  if (ulLastMillis > millis())     //Fallback! --> millis() overflow after 50 days
  { 
    ulLastMillis = millis();
  }
  
  iAdcRawPressure = analogRead(PressureSensor);
  fPressureVoltage = ((3.3/1024)*iAdcRawPressure);

    lcd.setCursor(0, 0);                // Cursor to position: char/line
    lcd.print("Druck: ");
    lcd.print(fPressureVoltage);
    lcd.print("V");
    delay(500); 

  if (millis() > (ulLastMillis+5000))  // Update every 5s
  {
    ulLastMillis = millis();
    druck = fPressureVoltage;
  }

  if (fPressureVoltage > 2)   //send SMS if voltage > 2V
  {
    Serial.println(fPressureVoltage);
    
    Serial.println("StarteSetup");
    Serial.println("SMS Message Sender");

#ifdef DoSMS
    bool connected = false;
    while (!connected) {
      if (gsmAccess.begin(SMSPIN) == GSM_READY) {
        connected = true;
      } else {
        Serial.println("Not connected");
        delay(1000);
      }
    }
    Serial.println("GSM initialized");   
#endif
    
    char remoteNum[20] = "+49172xxxxx";  // HandyNummer für SMS
    char txtMsg[200] = "Warnung!";
    
    Serial.println("SENDING");
    Serial.println("Message:");
    Serial.println(txtMsg);
    delay(1000);
    
#ifdef DoSMS
    // send the message
    sms.beginSMS(remoteNum);
    Serial.println("1");
    delay(2000);
    
    sms.print(txtMsg);
    Serial.println("2");
    delay(2000);
    
    sms.endSMS();
    Serial.println("3");
    delay(2000);

    Serial.println("\nCOMPLETE!\n");
    delay(2000);

    //Reconnect to Arduino cloud --- like this???
    //ArduinoCloud.begin(ArduinoIoTPreferredConnection) ???;    
#endif
    
  }
}

Absturz des Programms:

Sende SMS (2x)
SendeSMS2

Wenn Du genau in Deinen Code schaust, wirst Du feststellen, das mit jedem Durchllauf IMMER(!)
dieser Teil ausgeführt wird.

    char remoteNum[20] = "+49172xxxxx";  // HandyNummer für SMS
    char txtMsg[200] = "Warnung!";
    
    Serial.println("SENDING");
    Serial.println("Message:");
    Serial.println(txtMsg);
    delay(1000);

Es gibt ja keine Bedinung, die der Ausführung widerspricht.

NÖ!
Das Dingens stürtzt wohl nich ab.
Ergänze Deine Zeile 54

  ArduinoCloud.begin(ArduinoIoTPreferredConnection);

neu:

  ArduinoCloud.begin(ArduinoIoTPreferredConnection, false);

Hallo my_xy_project,

vielen Dank für deine Antwort.
Der ganze untere Programmteil wird ja nur ausgeführt, wenn die Bedingung:
if (fPressureVoltage > 2) //send SMS if voltage > 2V
erfüllt ist. Das da bei jedem Durchlauf dann alles wieder neu gesetzt wird ist mir für meinen Test gerade nicht so wichtig. Bis der Teil durch ist habe ich den Wert wieder auf weniger als 2V gedreht.
(sorry für die etwas unübersichtlichen Code-Einrückungen)

Mit der Änderung:
ArduinoCloud.begin(ArduinoIoTPreferredConnection,false);
klappt das SMS Versenden endlich. Da hat wohl während des Versendens der Watchdog zugeschlagen.

Hast du auch noch einen guten Tipp für mich wie ich nach der SMS meine Daten weiter in die Cloud senden kann?
Unter der Annahme der Wert liegt dann wieder innerhalb des legalen Bereicht...

Momentan bekomme ich diese Meldung, aber es kommt auch nach dem 200ten Versuch keine Verbindung zustande.

Eins nach dem anderen.

Ja, da hat der WDT zugeschlagen.
Der MUSS(!) aber wieder aktiviert werden.
Also überlege, was DU tun kannst.
Und dann, wenn der WDT nicht auslöst gibt es auch kein TimeOut.
Der Reset soll nämlich genau davor schützen, das durch ein (unbeabsichtigtes) TimeOut ein ConnectionClose und kein initiales reConnect erfolgt.

OK, dann bleiben wir erst mal beim Watchdog... der muss also aktiv bleiben.
Dazu fallen mit nur zwei Möglichkeiten ein um ein TimeOut zu verhindern:

  1. Ich muss den Watchdog zwischenzeitlich zurück setzten, während der SMS Kram läuft.
  2. Ich muss die Druchlaufzeit verkürzen, damit der Watchdog rechtzeitig wieder zurück gesetzt wird.

Zu (1) habe ich gelesen, das ArduinoIoTCloud.update() den WDT zurück setzt, aber das wird bestimmt nicht alles sein... die Durchlaufzeit zum Senden der SMS beträgt ca. 15s da müsste der WDT schon zuschlagen, wenn er nicht noch irgendwo resettet wird.

(2) konnte ich recht einfach realisieren, in dem ich meine ganzen Delay-Zeiten die ich da eingebaut hatte wieder entfernt habe. Das hat jetzt den Effekt, das der SMS-Versand bei aktivem Watchdog funktioniert.
Am Ende sieht es dann so aus wie oben auf dem Bild von gestern, dass die Verbindung zur Cloud unterbrochen ist und Versuche neu zu verbinden nicht erfolgreich sind.

Ne.
Mir fällt noch ne Dritte ein.
Und die ist die Wirksamste.

Schau in den Code.
Rechne zusammen wieviele Sekunden Du allein mit den Delays verbratest.
:slight_smile:

klar, das waren 10s die jetzt raus sind... aber was genau meinst du denn?

Jetzt müsste - wenn die delays raus sind der WDT frühzeitig zurück gesetzt werden.
Also.
Jetzt das false wieder aus der Initialisierung und schau, was passiert.

OK, ich hatte den Code nicht gepostet, aber genau das habe ich getan.
Ich habe alle Delays entfernt und das "false" auch.
Damit kommt die SMS durch und der WDT ist an :+1:

Jetzt muss ich nur irgendwie wieder zurück zum Senden in die Cloud...

Erstmal musste noch den Klassiker bereinigen!

  if (millis() > (ulLastMillis+5000))  // Update every 5s
  {
    ulLastMillis = millis();
    druck = fPressureVoltage;
  }

Denn das hier:

  if (ulLastMillis > millis())     //Fallback! --> millis() overflow after 50 days
  { 
    ulLastMillis = millis();
  }

ist absolut überflüssig, kontraproduktiv und was weiss nicht alles...

Und dann ist der Codeteil:

#ifdef DoSMS
    bool connected = false;
    while (!connected) {
      if (gsmAccess.begin(SMSPIN) == GSM_READY) {
        connected = true;
      } else {
        Serial.println("Not connected");
        delay(1000);
      }
    }
    Serial.println("GSM initialized");   
#endif
    
    char remoteNum[20] = "+49172xxxxx";  // HandyNummer für SMS
    char txtMsg[200] = "Warnung!";
    
    Serial.println("SENDING");
    Serial.println("Message:");
    Serial.println(txtMsg);
    delay(1000);
    
#ifdef DoSMS
    // send the message
    sms.beginSMS(remoteNum);
    Serial.println("1");
    delay(2000);
    
    sms.print(txtMsg);
    Serial.println("2");
    delay(2000);
    
    sms.endSMS();
    Serial.println("3");
    delay(2000);

    Serial.println("\nCOMPLETE!\n");
    delay(2000);

    //Reconnect to Arduino cloud --- like this???
    //ArduinoCloud.begin(ArduinoIoTPreferredConnection) ???;    
#endif

als switch / case zu überarbeiten.
Weil wenn die SMS länger braucht, kickt es Dich wieder weg.
Das lässt sich vermeiden.

Vielen Dank für deine Zeit und deine Hilfe :grinning:

Habe da ein bisschen "gefummelt" und erkannt, das ich die Funktion
gsmAccess.begin(SMSPIN)
und die ganze while-Schleife überhaupt nicht brauche. Wenn ich bereits verbunden bin sorgt diese Funktion dann dafür das meine Verbindung verloren geht.
Jetzt (ohne das "while") kann ich fröhlich eine SMS nach der anderen versenden und es läuft einfach weiter :+1:

Vielleicht könntest du mir aber noch kurz erklären, warum du den Teil mit den "millis()" für überflüssig/unnötig... hälst.
Ich würde darüber später gern die Datenmenge reduzieren und nur 1x pro Stunde meine Werte senden wenn alles in Ordnung ist, und ggf. kleinere Intervalle setzten wenn die Messwerte in einem "interessanten" Berich liegen.
Wenn der Wert nach 50Tagen überläuft sollte das doch auch abgefangen werden, ... oder?

Nein. Wenn man das richtig macht, dann geht das auch nach 49 Tagen +x ganz normal weiter.

Es gibt eine gute Erklärung in einem pdf, welches ich allen ans Herz lege:
https://www.arduinoforum.de/code-referenz
Dort einfach runterladen und durchlesen - nicht auswendig lernen.

Eine weitere Grundlage ist das Beispiel "blinkwithoutdelay" - DATEI - BEISPIELE - 02. DIGITAL->

Ich hatte gestern schon was fertig - heute sitze ich woanders...
Na mach mal. Wir können ja später vergleichen :wink:

Jo, verstehe... millis() Wert ist unsigned, und wenn man das auch als unsigned betrachte läuft es nach einem Überlauf auch weiter, weil:
(ein ganz kleine Wert) - (ein ganz großer Wert) immer noch ein ganz großer Wert ist, und damit jede Intervallbedingung erfüllt sein sollte.

Sehr hilfreiches PDF, danke auch dafür.