Problem mit weiterer include-Datei

Ich möchte den folgenden Sketch: https://youtu.be/OJcGY4ySs4o mit einer RTC erweitern und habe folgendes Problem:

  • mit Einfügen einer weiteren include-Datei z. B. : RTCLib.h oder Wire.h wird der Sketch ohne Fehlermeldung kompiliert, aber der Programmablauf ist fehlerhaft. Die SMS wird unvollständig gesendet und die Anzeige im Seriellen Monitor ist bei der Funktion Serial.println(GetRegisteredPhoneNumbersList()); unvollständig. Leider habe ich bisher keine Hinweise gefunden.

Hallo und willkommen.
Bitte zeige hier deinen Sketch in Code-Tags, damit wir sehen, wie du es programmiert hast.
Zeige ebenso die komplette Meldung wie du sie erwartest und wie sie dann gezeigt wird.

Zuwenig RAM?

Wird mehr RAM benötigt als physisch zur Verfügung steht?
Welchen RAM-Verbrauch wird nach dem Kompilieren angezeigt?

Grüße Uwe

Nach dem Kompilieren bekomme ich folgendes angezeigt:
Der Sketch verwendet 14910 Bytes (48%) des Programmspeicherplatzes. Das Maximum sind 30720 Bytes.
Globale Variablen verwenden 1342 Bytes (65%) des dynamischen Speichers, 706 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.
"C:\Users\witka\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/bin/avrdude" "-CC:\Users\witka\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf" -v -V -patmega328p -carduino "-PCOM4" -b57600 -D "-Uflash:w:C:\Users\witka\AppData\Local\Temp\arduino\sketches\2EF06C7E37F66D6FCC892CD88AE8BEC0/Falle_Ard.ino.hex:i"


```cpp
//#include <RTClib.h>
#include <SoftwareSerial.h>
#include <EEPROM.h>
//#include <Wire.h>




//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
const int totalPhoneNo = 5;
const byte phoneLength = 14;
const int debounceDelay = 50; // 50 ms delay to wait until stable read
//total memory consumed by phone numbers in EEPROM
const byte totalMemory = (phoneLength * 5) - 1;
//set starting address of each phone number in EEPROM
int offsetPhone[totalPhoneNo] = {0,phoneLength,phoneLength*2,phoneLength*3,phoneLength*4};
//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
int jj = 0;
int mon = 0;
int dy = 0;
int ho = 0;
int mm = 0;
int se = 0;
//------------------------------------------------
#define Power_on_SMS 16                                  // Ausgang für Aktivierung SIM800-Modul
#define Control_LED 15
#define Magnet_on 14                                     // Ausgang für Ansteuerung Magnet
#define CLOCK_INTERRUPT_PIN 3                             // Der Pin ist mit dem Anschluss SQW vom DS3231 verbunden.
#define PIR_INTERRUPT_PIN 2

//GSM Module RX pin to Arduino 3
//GSM Module TX pin to Arduino 2
#define rxPin 4
#define txPin 5
#define RESET_PIN 6
#define pir_sensor 13
SoftwareSerial sim800(rxPin,txPin);
//the pin that the pir sensor is atteched to


volatile int PIRState = LOW;         // Variable für den Status PIR-Interrupt
  
  
//Uhr DS3231
//RTC_DS3231 rtc;   
//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
//#define BUTTON_1 14
//#define BUTTON_2 15
//#define BUTTON_3 16
//#define BUTTON_4 17

#define RELAY_1 7
#define RELAY_2 8
#define RELAY_3 9
#define RELAY_4 10

boolean STATE_RELAY_1 = 1;
boolean STATE_RELAY_2 = 1;
boolean STATE_RELAY_3 = 1;
boolean STATE_RELAY_4 = 1;
//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
boolean isReply = false;
boolean simflag = false;
//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM

//------------------------------------------------
const unsigned long OneMinute = 60UL * 1000UL;
const unsigned long OneHour = 60UL * OneMinute;
const unsigned long TwentyFourHours = 24 * OneHour;
//The relay will turn OFF after stopTime end.
//stopTime can be set by sms.
//set the default stopTime to 1 hour
unsigned long stopTime = 3 * OneMinute;
unsigned long startTime = 0;
unsigned long stopPIR = 2 * OneMinute; // Zeit für Bewegungsmelder 
unsigned long startPIR = 0;
//------------------------------------------------

/*******************************************************************************
 * getResponse function
 ******************************************************************************/
boolean getResponse(String expected_answer, unsigned int timeout=1000,boolean reset=false){
  boolean flag = false;
  String response = "";
  unsigned long previous;
  //*************************************************************
  for(previous=millis(); (millis() - previous) < timeout;){
    while(sim800.available()){
      response = sim800.readString();
      //----------------------------------------
      //Used in resetSIM800L function
      //If there is some response data
      if(response != ""){
        Serial.println(response);
        if(reset == true)
          return true;
      }
      //----------------------------------------
      if(response.indexOf(expected_answer) > -1){
        return true;
      }
    }
  }
  //*************************************************************
  return false;
}
//---------------------------------------------------------------------------------------------
boolean tryATcommand(String cmd, String expected_answer, int timeout, int total_tries){
  TryAgain:
  //*************************************************************
  for(int i=1; i<=total_tries; i++){
    sim800.println(cmd);
    if(getResponse(expected_answer, timeout) == true){
      break;
    }
    else {
      Serial.print(".");
    }    
    if(i == total_tries){
      Serial.println("Faild! Resetting the Module");
      digitalWrite(RESET_PIN, LOW);
      delay(100);
      digitalWrite(RESET_PIN, HIGH);
      goto TryAgain;
    }
  }
  //*************************************************************
}
//---------------------------------------------------------------------------------------------
boolean resetSIM800(){
  digitalWrite(RESET_PIN, LOW);
  delay(100);
  digitalWrite(RESET_PIN, HIGH);
  
  boolean flag = false;
  for(int i=1; i<=20; i++){
    sim800.println("ATE");
    Serial.print(".");
    if(getResponse("NULL", 1000, true) == true)
      {flag = true; break;}
  }
  sim800.println("ATE");
  if(flag == true){
    for(int i=1; i<=20; i++){
      if(getResponse("SMS Ready", 15000) == true)
        {flag = true; break;}
    }
  }
  
}

/*******************************************************************************
 * setup function
 ******************************************************************************/
void setup() {
  //-----------------------------------------------------
  pinMode(pir_sensor, INPUT);                             // initialize sensor as an input
  pinMode(Magnet_on, OUTPUT);
  pinMode(Power_on_SMS, OUTPUT);
  //-----------------------------------------------------
  //pinMode(BUTTON_1, INPUT_PULLUP);
  //pinMode(BUTTON_2, INPUT_PULLUP);
  //pinMode(BUTTON_3, INPUT_PULLUP);
  //pinMode(BUTTON_4, INPUT_PULLUP);

  pinMode(RESET_PIN, OUTPUT);

  pinMode(PIR_INTERRUPT_PIN, INPUT);
  pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);

  pinMode(RELAY_1, OUTPUT);                               //Relay 1
  pinMode(RELAY_2, OUTPUT);                               //Relay 2
  pinMode(RELAY_3, OUTPUT);                               //Relay 3
  pinMode(RELAY_4, OUTPUT);                               //Relay 4

  digitalWrite(RELAY_1, HIGH);
  digitalWrite(RELAY_2, HIGH);
  digitalWrite(RELAY_3, HIGH);
  digitalWrite(RELAY_4, HIGH);
  
  
  delay(100);

  detachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN));                         // externe Interrupte deaktivieren
  //attachInterrupt(digitalPinToInterrupt(PIR_INTERRUPT_PIN), pin_ISR, RISING);          // Der Bewegungsmelder soll einen Interrupt auslösen, Rising
  detachInterrupt(digitalPinToInterrupt(PIR_INTERRUPT_PIN));
  PIRState = LOW;
  //-----------------------------------------------------
  Serial.begin(9600);
  Serial.println("Arduino serial initialize");
  //-----------------------------------------------------
  sim800.begin(9600);
  Serial.println("SIM800L software serial initialize");
  resetSIM800();
  tryATcommand("AT","OK",1000,20);
  tryATcommand("AT+CMGF=1","OK",1000,20);
  tryATcommand("AT+CNMI=1,2,0,0,0","OK",1000,20);
  //-------------------------------------------------------------------
  LoadStateEEPROM();
  //-------------------------------------------------------------------
  /*if(resetSIM800L() == false)
  { Serial.println("SIM800L Not Ready"); }
  sim800.println("AT");
  getResponse("OK",1000);
  sim800.println("AT+CMGF=1");
  getResponse("OK",1000);
  sim800.println("AT+CNMI=1,2,0,0,0");
  getResponse("OK",1000);*/
  //delete all sms
  sim800.println("AT+CMGD=1,4");
  delay(1000);
  sim800.println("AT+CMGDA= \"DEL ALL\"");
  delay(1000);
  //-------------------------------------------------------------------
  Serial.println(GetRegisteredPhoneNumbersList());
  //-------------------------------------------------------------------
}


/*******************************************************************************
 * Loop Function
 ******************************************************************************/
void loop() {
//------------------------------------------------------------------------------
if(simflag == false){
  SMS_Time();
}
//------------------------------------------------------------------------------
SMCR |=(1<<2);                             //enable sleep
  SMCR |=1;  
  ADCSRA &=~(1<<7);                         //disable ADC
  MCUCR |=(3<<5);                          //disable BOD
  MCUCR =(MCUCR &~(1<<5))|(1<<6);
  asm volatile("sleep");

Serial.println("loop");
//check_Time();
//listen_push_buttons();

/*******************************************************************************
 /* Interrupt Abfrage PIR
 ******************************************************************************/
if (PIRState == HIGH) 
    {   
    //detachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN));    // externe Interrupte deaktivieren
    detachInterrupt(digitalPinToInterrupt(PIR_INTERRUPT_PIN));
    digitalWrite(Magnet_on, HIGH);
    digitalWrite(Power_on_SMS, HIGH);
    
    Serial.println("Loop Bewegungsmelder");
    //detachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN));
    Serial.println("Magnet wird für 1 Sekunde eingeschaltet");
    //delay(500);
    Serial.println("SIM-Modul wird für 30 Sekunden eingeschaltet");
    digitalWrite(Magnet_on, LOW);
    Serial.println();
    smsaktiv();
    digitalWrite(Power_on_SMS, LOW);
    Serial.println("Loop Bewegungsmelder beendet");
    //rtc.clearAlarm(1);
    PIRState = LOW;
    }
//------------------------------------------------------------------------------
} //main loop ends


void pin_ISR() 
  {
  PIRState = HIGH; 
  Serial.println("Interrupt");
  }
   
/*******************************************************************************
 * GetRegisteredPhoneNumbersList function:
 ******************************************************************************/
String GetRegisteredPhoneNumbersList(){
  String text = "Registered Numbers List: \r\n";
  String temp = "";
  for(int i = 0; i < totalPhoneNo; i++){
    temp = readFromEEPROM(offsetPhone[i]);
    if(temp == "")
      { text = text + String(i+1)+". Empty\r\n"; }
    else if(temp.length() != phoneLength)
      { text = text + String(i+1)+". Wrong Format\r\n"; }
    else
      {text = text + String(i+1)+". "+temp+"\r\n";}
  }

  return text;
}
  
/*******************************************************************************
 * RegisterPhoneNumber function:
 ******************************************************************************/
void RegisterPhoneNumber(int index, String eeprom_phone, String caller_id){
  if(eeprom_phone.length() == phoneLength){
    writeToEEPROM(offsetPhone[index-1],eeprom_phone);
    String text = "Phone"+String(index)+" is Registered: ";
    //text = text + phoneNumber;
    Serial.println(text);
    Reply(text, caller_id);
  }
  else {
    String text = "Error: Phone number must be "+String(phoneLength)+" digits long";
    Serial.println(text);
    Reply(text, caller_id);
  }
}

/*******************************************************************************
 * UnRegisterPhoneNumber function:
 ******************************************************************************/
void DeletePhoneNumber(int index, String caller_id){
  writeToEEPROM(offsetPhone[index-1],"");
  String text = "Phone"+String(index)+" is deleted";
  Serial.println(text);
  Reply(text, caller_id);
}
/*******************************************************************************
 * DeletePhoneNumberList function:
 ******************************************************************************/
void DeletePhoneNumberList(){
  for (int i = 0; i < totalPhoneNo; i++){
    writeToEEPROM(offsetPhone[i],"");
  }
}

/*******************************************************************************
 * SMS empfangen function:
 * Wird nach dem Einschalten für ca. 2 Minuten aktiv
 ******************************************************************************/
void SMS_Time() { 
  for(int n = 0; n < 50; n++){
      digitalWrite(Control_LED, HIGH);
      delay(1000);
      digitalWrite(Control_LED, LOW);
      delay(1000);

      while(sim800.available()){
        String response = sim800.readString();
        Serial.println(response);
  //__________________________________________________________________________
  //if there is an incoming SMS
        if(response.indexOf("+CMT:") > -1){
          String callerID = getCallerID(response);
          String cmd = getMsgContent(response);
    //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    //this if statement will execute only if sim800l received "r" command 
    //and there will be no any phone number stored in the EEPROM
            if(cmd.equals("r")){
              String admin_phone = readFromEEPROM(offsetPhone[0]);
              if(admin_phone.length() != phoneLength){
                RegisterPhoneNumber(1, callerID, callerID);
                unsigned int index, index2;
                index = response.lastIndexOf(",");
                index2 = response.indexOf(",");
                Serial.println(response.substring(index-8, index));
                String yy_tmp = response.substring(index-8, index-6);
                jj = 2000 + yy_tmp.toInt();
                yy_tmp = response.substring(index-5, index-3);
                mon = yy_tmp.toInt();
                yy_tmp = response.substring(index-2, index);
                dy = yy_tmp.toInt();
                yy_tmp = response.substring(index+1, index+3);
                ho = yy_tmp.toInt();
                break;
              }
            else {
              String text = "Error: Admin phone number is failed to register";
              Serial.println(text);
              Reply(text, callerID);
              break;
            }
      }
    //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    //The action is performed only if the caller ID will matched with
    //any one of the phone numbers stored in the eeprom.
      if(comparePhone(callerID)){
        doAction(cmd, callerID);
      //delete all sms
        sim800.println("AT+CMGD=1,4");
        delay(1000);
        sim800.println("AT+CMGDA= \"DEL ALL\"");
        delay(1000);
      }
      else {
        String text = "Error: Please register your phone number first";
        Serial.println(text);
        Reply(text, callerID);
      }
    //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  
    }

  }
//------------------------------------------------------------------------------
  while(Serial.available())  {
    String response = Serial.readString();
    if(response.indexOf("clear") > -1){
      Serial.println(response);
      DeletePhoneNumberList();
      Serial.println(GetRegisteredPhoneNumbersList());
      break;
    }
    sim800.println(response);
  }
Serial.println("while Schleife");
}
simflag = true;
Serial.println("simflag");
attachInterrupt(digitalPinToInterrupt(PIR_INTERRUPT_PIN), pin_ISR, RISING);          // Der Bewegungsmelder soll einen Interrupt auslösen, Rising
}

void smsaktiv(){
     Serial.println("Programm smsaktiv");
     //delay(500);
    } 

/*******************************************************************************
 * doAction function:
 * Performs action according to the received sms
 ******************************************************************************/
void doAction(String cmd, String caller_id){
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  if(cmd == "1on"){
    controlRelayGSM(1, RELAY_1,STATE_RELAY_1 = LOW,caller_id);
    startTime = millis();
  }
  else if(cmd == "1off"){
    controlRelayGSM(1, RELAY_1,STATE_RELAY_1 = HIGH,caller_id);
    startTime = 0;
  }
  
  //dr=50  (50 minutes)
  String temp_cmd = cmd.substring(0, 3);
  if(temp_cmd.equals("dr=")){
    String temp_duration = cmd.substring(3, cmd.length());
    long duration = temp_duration.toInt();
    duration = duration * OneMinute;
    //-------------------------------------
    if(duration > OneMinute){
      if(duration > TwentyFourHours)
        {stopTime = TwentyFourHours;}
      stopTime = duration;
      String text = "Relay Stop Timer is set: "+String(stopTime/60000)+" Minutes";
      Serial.println(text);
      Reply(text,caller_id);
      
    }
    //-------------------------------------
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  
  
  else if(cmd == "2on"){  
    controlRelayGSM(2, RELAY_2,LOW,caller_id);
    STATE_RELAY_2 = HIGH;
    startPIR = millis();
  }
  else if(cmd == "2off"){
    controlRelayGSM(2, RELAY_2,HIGH,caller_id);
    STATE_RELAY_2 = LOW;
    startPIR = 0;
  }
  //dr=50  (50 minutes) Zeit für Bewegungsmelder kann mit Befehl bw= eingegeben werden.
  String temp_cmd1 = cmd.substring(0, 3);
  if(temp_cmd1.equals("bw=")){
    String temp_duration = cmd.substring(3, cmd.length());
    long duration = temp_duration.toInt();
    duration = duration * OneMinute;
    //-------------------------------------
    if(duration > OneMinute){
      if(duration > TwentyFourHours)
        {stopPIR = TwentyFourHours;}
      stopPIR = duration;
      String text = "Bewegungsmelder Zeitdauer: "+String(stopPIR/60000)+" Minutes";
      Serial.println(text);
      Reply(text,caller_id);
      
    }
    //-------------------------------------
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd == "3on"){  
    controlRelayGSM(3, RELAY_3,LOW,caller_id);
    STATE_RELAY_3 = HIGH;
  }
  else if(cmd == "3off"){
    controlRelayGSM(3, RELAY_3,HIGH,caller_id);
    STATE_RELAY_3 = LOW;
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd == "4on"){  
    controlRelayGSM(4, RELAY_4,LOW,caller_id);
    STATE_RELAY_4 = HIGH;
  }
  else if(cmd == "4off"){
    controlRelayGSM(4, RELAY_4,HIGH,caller_id);
    STATE_RELAY_4 = LOW;
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd == "stat=1"){
    sendStatus(1, STATE_RELAY_1,caller_id);
  }
  else if(cmd == "stat=2"){
    sendStatus(2, STATE_RELAY_2,caller_id);
  }
  else if(cmd == "stat=3"){
    sendStatus(3, STATE_RELAY_3,caller_id);
  }
  else if(cmd == "stat=4"){
    sendStatus(4, STATE_RELAY_4,caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd.indexOf("r2=") > -1){
    RegisterPhoneNumber(2, getNumber(cmd), caller_id);
  }
  else if(cmd.indexOf("r3=") > -1){
    RegisterPhoneNumber(3, getNumber(cmd), caller_id);
  }
  else if(cmd.indexOf("r4=") > -1){ 
    RegisterPhoneNumber(4, getNumber(cmd), caller_id);
  }
  else if(cmd.indexOf("r5=") > -1){
    RegisterPhoneNumber(5, getNumber(cmd), caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd == "list"){
    String list = GetRegisteredPhoneNumbersList();
    Serial.println(list);
    Reply(list, caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  //else if(cmd == "del=1"){  
    //DeletePhoneNumber(1, caller_id);
  //}
  else if(cmd == "del=2"){  
    DeletePhoneNumber(2, caller_id);
  }
  else if(cmd == "del=3"){  
    DeletePhoneNumber(3, caller_id);
  }
  else if(cmd == "del=4"){  
    DeletePhoneNumber(4, caller_id);
  }
  else if(cmd == "del=5"){  
    DeletePhoneNumber(5, caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd == "del=all"){
    DeletePhoneNumberList();
    String text = "All the phone numbers are deleted.";
    Serial.println(text);
    Reply(text, caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else{
    String text = "Error: Unknown command: "+cmd;
    Serial.println(text);
    Reply(text, caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
}

/*******************************************************************************
 * Abfrage Bewegungsmelder und zeitgesteuerten Relais 1 function:
 ******************************************************************************/
//__________________________________________________________________________
/*void check_Time(){
  int val = digitalRead(pir_sensor);  // read sensor value
  if (val == HIGH) {                  // check if the sensor is HIGH
    //state = HIGH;
    Serial.println("Motion detected!");
    Serial.println("Relay_2 wird eingeschaltet");
    delay(1000);
    STATE_RELAY_2 = 0;
    digitalWrite(RELAY_2, LOW);
    startPIR = millis();
  }
//check if the PIR relay_2 is ON
if(STATE_RELAY_2 == 0 and startPIR > 0){
  unsigned long currentMillis2 = millis();
  //____________________________________________
  if(currentMillis2 - startPIR >= stopPIR) {
    STATE_RELAY_2 = 1;
    digitalWrite(RELAY_2, HIGH);
    startPIR = 0;
    Serial.println("Relay_2 wird ausgeschaltet");
    }
  }
  //____________________________________________
//check if the relay_1 is ON
if(STATE_RELAY_1 == 0 and startTime > 0){
  unsigned long currentMillis = millis();
  //____________________________________________
  if(currentMillis - startTime >= stopTime) {
    STATE_RELAY_1 = 1;
    digitalWrite(RELAY_1, HIGH);
    startTime = 0;
    Serial.println("Relay_1 wird ausgeschaltet");
    }
  }
  }*/
  //____________________________________________

/*******************************************************************************
 * listen_push_buttons function:
 ******************************************************************************/
/*void listen_push_buttons(){
    if(debounce(BUTTON_1) == LOW){
      control_relay(1, RELAY_1, STATE_RELAY_1);
    }
    else if (debounce(BUTTON_2) == LOW){
      control_relay(2, RELAY_2, STATE_RELAY_2);
    }
    else if (debounce(BUTTON_3) == LOW){
      control_relay(3, RELAY_3, STATE_RELAY_3);
    }
    else if (debounce(BUTTON_4) == LOW){
      control_relay(4, RELAY_4, STATE_RELAY_4);
    }
}*/
void control_relay(int relay_no, int relay_pin, boolean &status){
  delay(200);
  String text = (status)? "OFF" : "ON";
  status = !status;
  digitalWrite(relay_pin, status);
  Serial.println("Relay"+String(relay_no)+" is "+text);
  delay(50);
  EEPROM.update(totalMemory+relay_no,status);
}

/*******************************************************************************
 * Debounce für Taster function:
 ******************************************************************************/
/*boolean debounce(int pin){
	boolean state;
	boolean previousState;
	previousState = digitalRead(pin); // store switch state

	for(int counter=0; counter < debounceDelay; counter++){
	delay(1); // wait for 1 ms
	state = digitalRead(pin); // read the pin
		if( state != previousState){
		counter = 0; // reset the counter if the state changes
		previousState = state; // save the current state
		}
	}
	
	return state;	// now return the stable state
}*/


/*******************************************************************************
 * getCallerID function:
 ******************************************************************************/
String getCallerID(String buff){
//+CMT: "+923001234567","","22/05/20,11:59:15+20"
//Hello
  unsigned int index, index2;
  index = buff.indexOf("\"");
  index2 = buff.indexOf("\"", index+1);
  String callerID = buff.substring(index+1, index2);
  callerID.trim();
  //Serial.print("index+1= "); Serial.println(index+1);
  //Serial.print("index2= "); Serial.println(index2);
  //Serial.print("length= "); Serial.println(callerID.length());
  Serial.println("Caller ID: "+callerID);
  return callerID;
}
/*******************************************************************************
 * getMsgContent function:
 ******************************************************************************/
String getMsgContent(String buff){
  //+CMT: "+923001234567","","22/05/20,11:59:15+20"
  //Hello  
  unsigned int index, index2;
  index = buff.lastIndexOf("\"");
  index2 = buff.length();
  String command = buff.substring(index+1, index2);
  command.trim();
  command.toLowerCase();
  //Serial.print("index+1= "); Serial.println(index+1);
  //Serial.print("index2= "); Serial.println(index2);
  //Serial.print("length= "); Serial.println(msg.length());
  Serial.println("Command:"+command);
  return command;
}
/*******************************************************************************
 * getNumber function:
 ******************************************************************************/
String getNumber(String text){
  //r=+923001234567
  String temp = text.substring(3, 17);    //17 statt 16, weil 14-stellige Telefonnummer
  //Serial.println(temp);
  temp.trim();
  return temp;
}


/*******************************************************************************
 * controlRelayGSM function:
 ******************************************************************************/
void controlRelayGSM(int relay_no, int relay_pin, boolean status, String caller_id){
  digitalWrite(relay_pin, status);
  EEPROM.update(totalMemory+relay_no,status);
  String text = (status)? "OFF" : "ON";
  text = "Relay "+String(relay_no)+" is " +text;
  Serial.println(text);
  Reply(text, caller_id);
}

/*******************************************************************************
 * sendStatus function:
 ******************************************************************************/
void sendStatus(int relay_no, boolean status, String caller_id){
  String text = (status)? "OFF" : "ON";
  text = "Relay "+String(relay_no)+" is " +text;
  Serial.println(text);
  Reply(text, caller_id);
}

/*******************************************************************************
 * Reply function
 * Send an sms
 ******************************************************************************/
void Reply(String text, String caller_id)
{
  //return;
    sim800.print("AT+CMGF=1\r");
    delay(1000);
    sim800.print("AT+CMGS=\""+caller_id+"\"\r");
    delay(1000);
    sim800.print(text);
    delay(100);
    sim800.write(0x1A); //ascii code for ctrl-26 //sim800.println((char)26); //ascii code for ctrl-26
    delay(1000);
    Serial.println("SMS Sent Successfully.");
}
/*******************************************************************************
 * writeToEEPROM function:
 * Store registered phone numbers in EEPROM
 ******************************************************************************/
void writeToEEPROM(int addrOffset, const String &strToWrite)
{
  //byte phoneLength = strToWrite.length();
  //EEPROM.write(addrOffset, phoneLength);
  for (int i = 0; i < phoneLength; i++)
    { EEPROM.write(addrOffset + i, strToWrite[i]); }
}

/*******************************************************************************
 * readFromEEPROM function:
 * Store phone numbers in EEPROM
 ******************************************************************************/
String readFromEEPROM(int addrOffset)
{
  //byte phoneLength = strToWrite.length();
  char data[phoneLength + 1];
  for (int i = 0; i < phoneLength; i++)
    { data[i] = EEPROM.read(addrOffset + i); }
  data[phoneLength] = '\0';
  return String(data);
}

/*******************************************************************************
 * comparePhone function:
 * compare phone numbers stored in EEPROM
 ******************************************************************************/
boolean comparePhone(String number)
{
  boolean flag = 0;
  String tempPhone = "";
  //--------------------------------------------------
  for (int i = 0; i < totalPhoneNo; i++){
    tempPhone = readFromEEPROM(offsetPhone[i]);
    if(tempPhone.equals(number)){
      flag = 1;
      break;
    }
  }
  //--------------------------------------------------
  return flag;
}

void LoadStateEEPROM()
{
  STATE_RELAY_1 = EEPROM.read(totalMemory+1); delay(200);
  STATE_RELAY_2 = EEPROM.read(totalMemory+2); delay(200);
  STATE_RELAY_3 = EEPROM.read(totalMemory+3); delay(200);
  STATE_RELAY_4 = EEPROM.read(totalMemory+4); delay(200);
  
  digitalWrite(RELAY_1, STATE_RELAY_1);
  digitalWrite(RELAY_2, STATE_RELAY_2);
  digitalWrite(RELAY_3, STATE_RELAY_3);
  digitalWrite(RELAY_4, STATE_RELAY_4);
}  

//#include <RTClib.h>
#include <SoftwareSerial.h>
#include <EEPROM.h>
//#include <Wire.h>




//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
const int totalPhoneNo = 5;
const byte phoneLength = 14;
const int debounceDelay = 50; // 50 ms delay to wait until stable read
//total memory consumed by phone numbers in EEPROM
const byte totalMemory = (phoneLength * 5) - 1;
//set starting address of each phone number in EEPROM
int offsetPhone[totalPhoneNo] = {0,phoneLength,phoneLength*2,phoneLength*3,phoneLength*4};
//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
int jj = 0;
int mon = 0;
int dy = 0;
int ho = 0;
int mm = 0;
int se = 0;
//------------------------------------------------
#define Power_on_SMS 16                                  // Ausgang für Aktivierung SIM800-Modul
#define Control_LED 15
#define Magnet_on 14                                     // Ausgang für Ansteuerung Magnet
#define CLOCK_INTERRUPT_PIN 3                             // Der Pin ist mit dem Anschluss SQW vom DS3231 verbunden.
#define PIR_INTERRUPT_PIN 2

//GSM Module RX pin to Arduino 3
//GSM Module TX pin to Arduino 2
#define rxPin 4
#define txPin 5
#define RESET_PIN 6
#define pir_sensor 13
SoftwareSerial sim800(rxPin,txPin);
//the pin that the pir sensor is atteched to


volatile int PIRState = LOW;         // Variable für den Status PIR-Interrupt
  
  
//Uhr DS3231
//RTC_DS3231 rtc;   
//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
//#define BUTTON_1 14
//#define BUTTON_2 15
//#define BUTTON_3 16
//#define BUTTON_4 17

#define RELAY_1 7
#define RELAY_2 8
#define RELAY_3 9
#define RELAY_4 10

boolean STATE_RELAY_1 = 1;
boolean STATE_RELAY_2 = 1;
boolean STATE_RELAY_3 = 1;
boolean STATE_RELAY_4 = 1;
//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
boolean isReply = false;
boolean simflag = false;
//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM

//------------------------------------------------
const unsigned long OneMinute = 60UL * 1000UL;
const unsigned long OneHour = 60UL * OneMinute;
const unsigned long TwentyFourHours = 24 * OneHour;
//The relay will turn OFF after stopTime end.
//stopTime can be set by sms.
//set the default stopTime to 1 hour
unsigned long stopTime = 3 * OneMinute;
unsigned long startTime = 0;
unsigned long stopPIR = 2 * OneMinute; // Zeit für Bewegungsmelder 
unsigned long startPIR = 0;
//------------------------------------------------

/*******************************************************************************
 * getResponse function
 ******************************************************************************/
boolean getResponse(String expected_answer, unsigned int timeout=1000,boolean reset=false){
  boolean flag = false;
  String response = "";
  unsigned long previous;
  //*************************************************************
  for(previous=millis(); (millis() - previous) < timeout;){
    while(sim800.available()){
      response = sim800.readString();
      //----------------------------------------
      //Used in resetSIM800L function
      //If there is some response data
      if(response != ""){
        Serial.println(response);
        if(reset == true)
          return true;
      }
      //----------------------------------------
      if(response.indexOf(expected_answer) > -1){
        return true;
      }
    }
  }
  //*************************************************************
  return false;
}
//---------------------------------------------------------------------------------------------
boolean tryATcommand(String cmd, String expected_answer, int timeout, int total_tries){
  TryAgain:
  //*************************************************************
  for(int i=1; i<=total_tries; i++){
    sim800.println(cmd);
    if(getResponse(expected_answer, timeout) == true){
      break;
    }
    else {
      Serial.print(".");
    }    
    if(i == total_tries){
      Serial.println("Faild! Resetting the Module");
      digitalWrite(RESET_PIN, LOW);
      delay(100);
      digitalWrite(RESET_PIN, HIGH);
      goto TryAgain;
    }
  }
  //*************************************************************
}
//---------------------------------------------------------------------------------------------
boolean resetSIM800(){
  digitalWrite(RESET_PIN, LOW);
  delay(100);
  digitalWrite(RESET_PIN, HIGH);
  
  boolean flag = false;
  for(int i=1; i<=20; i++){
    sim800.println("ATE");
    Serial.print(".");
    if(getResponse("NULL", 1000, true) == true)
      {flag = true; break;}
  }
  sim800.println("ATE");
  if(flag == true){
    for(int i=1; i<=20; i++){
      if(getResponse("SMS Ready", 15000) == true)
        {flag = true; break;}
    }
  }
  
}

/*******************************************************************************
 * setup function
 ******************************************************************************/
void setup() {
  //-----------------------------------------------------
  pinMode(pir_sensor, INPUT);                             // initialize sensor as an input
  pinMode(Magnet_on, OUTPUT);
  pinMode(Power_on_SMS, OUTPUT);
  //-----------------------------------------------------
  //pinMode(BUTTON_1, INPUT_PULLUP);
  //pinMode(BUTTON_2, INPUT_PULLUP);
  //pinMode(BUTTON_3, INPUT_PULLUP);
  //pinMode(BUTTON_4, INPUT_PULLUP);

  pinMode(RESET_PIN, OUTPUT);

  pinMode(PIR_INTERRUPT_PIN, INPUT);
  pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);

  pinMode(RELAY_1, OUTPUT);                               //Relay 1
  pinMode(RELAY_2, OUTPUT);                               //Relay 2
  pinMode(RELAY_3, OUTPUT);                               //Relay 3
  pinMode(RELAY_4, OUTPUT);                               //Relay 4

  digitalWrite(RELAY_1, HIGH);
  digitalWrite(RELAY_2, HIGH);
  digitalWrite(RELAY_3, HIGH);
  digitalWrite(RELAY_4, HIGH);
  
  
  delay(100);

  detachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN));                         // externe Interrupte deaktivieren
  //attachInterrupt(digitalPinToInterrupt(PIR_INTERRUPT_PIN), pin_ISR, RISING);          // Der Bewegungsmelder soll einen Interrupt auslösen, Rising
  detachInterrupt(digitalPinToInterrupt(PIR_INTERRUPT_PIN));
  PIRState = LOW;
  //-----------------------------------------------------
  Serial.begin(9600);
  Serial.println("Arduino serial initialize");
  //-----------------------------------------------------
  sim800.begin(9600);
  Serial.println("SIM800L software serial initialize");
  resetSIM800();
  tryATcommand("AT","OK",1000,20);
  tryATcommand("AT+CMGF=1","OK",1000,20);
  tryATcommand("AT+CNMI=1,2,0,0,0","OK",1000,20);
  //-------------------------------------------------------------------
  LoadStateEEPROM();
  //-------------------------------------------------------------------
  /*if(resetSIM800L() == false)
  { Serial.println("SIM800L Not Ready"); }
  sim800.println("AT");
  getResponse("OK",1000);
  sim800.println("AT+CMGF=1");
  getResponse("OK",1000);
  sim800.println("AT+CNMI=1,2,0,0,0");
  getResponse("OK",1000);*/
  //delete all sms
  sim800.println("AT+CMGD=1,4");
  delay(1000);
  sim800.println("AT+CMGDA= \"DEL ALL\"");
  delay(1000);
  //-------------------------------------------------------------------
  Serial.println(GetRegisteredPhoneNumbersList());
  //-------------------------------------------------------------------
}


/*******************************************************************************
 * Loop Function
 ******************************************************************************/
void loop() {
//------------------------------------------------------------------------------
if(simflag == false){
  SMS_Time();
}
//------------------------------------------------------------------------------
SMCR |=(1<<2);                             //enable sleep
  SMCR |=1;  
  ADCSRA &=~(1<<7);                         //disable ADC
  MCUCR |=(3<<5);                          //disable BOD
  MCUCR =(MCUCR &~(1<<5))|(1<<6);
  asm volatile("sleep");

Serial.println("loop");
//check_Time();
//listen_push_buttons();

/*******************************************************************************
 /* Interrupt Abfrage PIR
 ******************************************************************************/
if (PIRState == HIGH) 
    {   
    //detachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN));    // externe Interrupte deaktivieren
    detachInterrupt(digitalPinToInterrupt(PIR_INTERRUPT_PIN));
    digitalWrite(Magnet_on, HIGH);
    digitalWrite(Power_on_SMS, HIGH);
    
    Serial.println("Loop Bewegungsmelder");
    //detachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN));
    Serial.println("Magnet wird für 1 Sekunde eingeschaltet");
    //delay(500);
    Serial.println("SIM-Modul wird für 30 Sekunden eingeschaltet");
    digitalWrite(Magnet_on, LOW);
    Serial.println();
    smsaktiv();
    digitalWrite(Power_on_SMS, LOW);
    Serial.println("Loop Bewegungsmelder beendet");
    //rtc.clearAlarm(1);
    PIRState = LOW;
    }
//------------------------------------------------------------------------------
} //main loop ends


void pin_ISR() 
  {
  PIRState = HIGH; 
  Serial.println("Interrupt");
  }
   
/*******************************************************************************
 * GetRegisteredPhoneNumbersList function:
 ******************************************************************************/
String GetRegisteredPhoneNumbersList(){
  String text = "Registered Numbers List: \r\n";
  String temp = "";
  for(int i = 0; i < totalPhoneNo; i++){
    temp = readFromEEPROM(offsetPhone[i]);
    if(temp == "")
      { text = text + String(i+1)+". Empty\r\n"; }
    else if(temp.length() != phoneLength)
      { text = text + String(i+1)+". Wrong Format\r\n"; }
    else
      {text = text + String(i+1)+". "+temp+"\r\n";}
  }

  return text;
}
  
/*******************************************************************************
 * RegisterPhoneNumber function:
 ******************************************************************************/
void RegisterPhoneNumber(int index, String eeprom_phone, String caller_id){
  if(eeprom_phone.length() == phoneLength){
    writeToEEPROM(offsetPhone[index-1],eeprom_phone);
    String text = "Phone"+String(index)+" is Registered: ";
    //text = text + phoneNumber;
    Serial.println(text);
    Reply(text, caller_id);
  }
  else {
    String text = "Error: Phone number must be "+String(phoneLength)+" digits long";
    Serial.println(text);
    Reply(text, caller_id);
  }
}

/*******************************************************************************
 * UnRegisterPhoneNumber function:
 ******************************************************************************/
void DeletePhoneNumber(int index, String caller_id){
  writeToEEPROM(offsetPhone[index-1],"");
  String text = "Phone"+String(index)+" is deleted";
  Serial.println(text);
  Reply(text, caller_id);
}
/*******************************************************************************
 * DeletePhoneNumberList function:
 ******************************************************************************/
void DeletePhoneNumberList(){
  for (int i = 0; i < totalPhoneNo; i++){
    writeToEEPROM(offsetPhone[i],"");
  }
}

/*******************************************************************************
 * SMS empfangen function:
 * Wird nach dem Einschalten für ca. 2 Minuten aktiv
 ******************************************************************************/
void SMS_Time() { 
  for(int n = 0; n < 50; n++){
      digitalWrite(Control_LED, HIGH);
      delay(1000);
      digitalWrite(Control_LED, LOW);
      delay(1000);

      while(sim800.available()){
        String response = sim800.readString();
        Serial.println(response);
  //__________________________________________________________________________
  //if there is an incoming SMS
        if(response.indexOf("+CMT:") > -1){
          String callerID = getCallerID(response);
          String cmd = getMsgContent(response);
    //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    //this if statement will execute only if sim800l received "r" command 
    //and there will be no any phone number stored in the EEPROM
            if(cmd.equals("r")){
              String admin_phone = readFromEEPROM(offsetPhone[0]);
              if(admin_phone.length() != phoneLength){
                RegisterPhoneNumber(1, callerID, callerID);
                unsigned int index, index2;
                index = response.lastIndexOf(",");
                index2 = response.indexOf(",");
                Serial.println(response.substring(index-8, index));
                String yy_tmp = response.substring(index-8, index-6);
                jj = 2000 + yy_tmp.toInt();
                yy_tmp = response.substring(index-5, index-3);
                mon = yy_tmp.toInt();
                yy_tmp = response.substring(index-2, index);
                dy = yy_tmp.toInt();
                yy_tmp = response.substring(index+1, index+3);
                ho = yy_tmp.toInt();
                break;
              }
            else {
              String text = "Error: Admin phone number is failed to register";
              Serial.println(text);
              Reply(text, callerID);
              break;
            }
      }
    //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    //The action is performed only if the caller ID will matched with
    //any one of the phone numbers stored in the eeprom.
      if(comparePhone(callerID)){
        doAction(cmd, callerID);
      //delete all sms
        sim800.println("AT+CMGD=1,4");
        delay(1000);
        sim800.println("AT+CMGDA= \"DEL ALL\"");
        delay(1000);
      }
      else {
        String text = "Error: Please register your phone number first";
        Serial.println(text);
        Reply(text, callerID);
      }
    //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  
    }

  }
//------------------------------------------------------------------------------
  while(Serial.available())  {
    String response = Serial.readString();
    if(response.indexOf("clear") > -1){
      Serial.println(response);
      DeletePhoneNumberList();
      Serial.println(GetRegisteredPhoneNumbersList());
      break;
    }
    sim800.println(response);
  }
Serial.println("while Schleife");
}
simflag = true;
Serial.println("simflag");
attachInterrupt(digitalPinToInterrupt(PIR_INTERRUPT_PIN), pin_ISR, RISING);          // Der Bewegungsmelder soll einen Interrupt auslösen, Rising
}

void smsaktiv(){
     Serial.println("Programm smsaktiv");
     //delay(500);
    } 

/*******************************************************************************
 * doAction function:
 * Performs action according to the received sms
 ******************************************************************************/
void doAction(String cmd, String caller_id){
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  if(cmd == "1on"){
    controlRelayGSM(1, RELAY_1,STATE_RELAY_1 = LOW,caller_id);
    startTime = millis();
  }
  else if(cmd == "1off"){
    controlRelayGSM(1, RELAY_1,STATE_RELAY_1 = HIGH,caller_id);
    startTime = 0;
  }
  
  //dr=50  (50 minutes)
  String temp_cmd = cmd.substring(0, 3);
  if(temp_cmd.equals("dr=")){
    String temp_duration = cmd.substring(3, cmd.length());
    long duration = temp_duration.toInt();
    duration = duration * OneMinute;
    //-------------------------------------
    if(duration > OneMinute){
      if(duration > TwentyFourHours)
        {stopTime = TwentyFourHours;}
      stopTime = duration;
      String text = "Relay Stop Timer is set: "+String(stopTime/60000)+" Minutes";
      Serial.println(text);
      Reply(text,caller_id);
      
    }
    //-------------------------------------
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  
  
  else if(cmd == "2on"){  
    controlRelayGSM(2, RELAY_2,LOW,caller_id);
    STATE_RELAY_2 = HIGH;
    startPIR = millis();
  }
  else if(cmd == "2off"){
    controlRelayGSM(2, RELAY_2,HIGH,caller_id);
    STATE_RELAY_2 = LOW;
    startPIR = 0;
  }
  //dr=50  (50 minutes) Zeit für Bewegungsmelder kann mit Befehl bw= eingegeben werden.
  String temp_cmd1 = cmd.substring(0, 3);
  if(temp_cmd1.equals("bw=")){
    String temp_duration = cmd.substring(3, cmd.length());
    long duration = temp_duration.toInt();
    duration = duration * OneMinute;
    //-------------------------------------
    if(duration > OneMinute){
      if(duration > TwentyFourHours)
        {stopPIR = TwentyFourHours;}
      stopPIR = duration;
      String text = "Bewegungsmelder Zeitdauer: "+String(stopPIR/60000)+" Minutes";
      Serial.println(text);
      Reply(text,caller_id);
      
    }
    //-------------------------------------
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd == "3on"){  
    controlRelayGSM(3, RELAY_3,LOW,caller_id);
    STATE_RELAY_3 = HIGH;
  }
  else if(cmd == "3off"){
    controlRelayGSM(3, RELAY_3,HIGH,caller_id);
    STATE_RELAY_3 = LOW;
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd == "4on"){  
    controlRelayGSM(4, RELAY_4,LOW,caller_id);
    STATE_RELAY_4 = HIGH;
  }
  else if(cmd == "4off"){
    controlRelayGSM(4, RELAY_4,HIGH,caller_id);
    STATE_RELAY_4 = LOW;
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd == "stat=1"){
    sendStatus(1, STATE_RELAY_1,caller_id);
  }
  else if(cmd == "stat=2"){
    sendStatus(2, STATE_RELAY_2,caller_id);
  }
  else if(cmd == "stat=3"){
    sendStatus(3, STATE_RELAY_3,caller_id);
  }
  else if(cmd == "stat=4"){
    sendStatus(4, STATE_RELAY_4,caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd.indexOf("r2=") > -1){
    RegisterPhoneNumber(2, getNumber(cmd), caller_id);
  }
  else if(cmd.indexOf("r3=") > -1){
    RegisterPhoneNumber(3, getNumber(cmd), caller_id);
  }
  else if(cmd.indexOf("r4=") > -1){ 
    RegisterPhoneNumber(4, getNumber(cmd), caller_id);
  }
  else if(cmd.indexOf("r5=") > -1){
    RegisterPhoneNumber(5, getNumber(cmd), caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd == "list"){
    String list = GetRegisteredPhoneNumbersList();
    Serial.println(list);
    Reply(list, caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  //else if(cmd == "del=1"){  
    //DeletePhoneNumber(1, caller_id);
  //}
  else if(cmd == "del=2"){  
    DeletePhoneNumber(2, caller_id);
  }
  else if(cmd == "del=3"){  
    DeletePhoneNumber(3, caller_id);
  }
  else if(cmd == "del=4"){  
    DeletePhoneNumber(4, caller_id);
  }
  else if(cmd == "del=5"){  
    DeletePhoneNumber(5, caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else if(cmd == "del=all"){
    DeletePhoneNumberList();
    String text = "All the phone numbers are deleted.";
    Serial.println(text);
    Reply(text, caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  else{
    String text = "Error: Unknown command: "+cmd;
    Serial.println(text);
    Reply(text, caller_id);
  }
  //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
}

/*******************************************************************************
 * Abfrage Bewegungsmelder und zeitgesteuerten Relais 1 function:
 ******************************************************************************/
//__________________________________________________________________________
/*void check_Time(){
  int val = digitalRead(pir_sensor);  // read sensor value
  if (val == HIGH) {                  // check if the sensor is HIGH
    //state = HIGH;
    Serial.println("Motion detected!");
    Serial.println("Relay_2 wird eingeschaltet");
    delay(1000);
    STATE_RELAY_2 = 0;
    digitalWrite(RELAY_2, LOW);
    startPIR = millis();
  }
//check if the PIR relay_2 is ON
if(STATE_RELAY_2 == 0 and startPIR > 0){
  unsigned long currentMillis2 = millis();
  //____________________________________________
  if(currentMillis2 - startPIR >= stopPIR) {
    STATE_RELAY_2 = 1;
    digitalWrite(RELAY_2, HIGH);
    startPIR = 0;
    Serial.println("Relay_2 wird ausgeschaltet");
    }
  }
  //____________________________________________
//check if the relay_1 is ON
if(STATE_RELAY_1 == 0 and startTime > 0){
  unsigned long currentMillis = millis();
  //____________________________________________
  if(currentMillis - startTime >= stopTime) {
    STATE_RELAY_1 = 1;
    digitalWrite(RELAY_1, HIGH);
    startTime = 0;
    Serial.println("Relay_1 wird ausgeschaltet");
    }
  }
  }*/
  //____________________________________________

/*******************************************************************************
 * listen_push_buttons function:
 ******************************************************************************/
/*void listen_push_buttons(){
    if(debounce(BUTTON_1) == LOW){
      control_relay(1, RELAY_1, STATE_RELAY_1);
    }
    else if (debounce(BUTTON_2) == LOW){
      control_relay(2, RELAY_2, STATE_RELAY_2);
    }
    else if (debounce(BUTTON_3) == LOW){
      control_relay(3, RELAY_3, STATE_RELAY_3);
    }
    else if (debounce(BUTTON_4) == LOW){
      control_relay(4, RELAY_4, STATE_RELAY_4);
    }
}*/
void control_relay(int relay_no, int relay_pin, boolean &status){
  delay(200);
  String text = (status)? "OFF" : "ON";
  status = !status;
  digitalWrite(relay_pin, status);
  Serial.println("Relay"+String(relay_no)+" is "+text);
  delay(50);
  EEPROM.update(totalMemory+relay_no,status);
}

/*******************************************************************************
 * Debounce für Taster function:
 ******************************************************************************/
/*boolean debounce(int pin){
	boolean state;
	boolean previousState;
	previousState = digitalRead(pin); // store switch state

	for(int counter=0; counter < debounceDelay; counter++){
	delay(1); // wait for 1 ms
	state = digitalRead(pin); // read the pin
		if( state != previousState){
		counter = 0; // reset the counter if the state changes
		previousState = state; // save the current state
		}
	}
	
	return state;	// now return the stable state
}*/


/*******************************************************************************
 * getCallerID function:
 ******************************************************************************/
String getCallerID(String buff){
//+CMT: "+923001234567","","22/05/20,11:59:15+20"
//Hello
  unsigned int index, index2;
  index = buff.indexOf("\"");
  index2 = buff.indexOf("\"", index+1);
  String callerID = buff.substring(index+1, index2);
  callerID.trim();
  //Serial.print("index+1= "); Serial.println(index+1);
  //Serial.print("index2= "); Serial.println(index2);
  //Serial.print("length= "); Serial.println(callerID.length());
  Serial.println("Caller ID: "+callerID);
  return callerID;
}
/*******************************************************************************
 * getMsgContent function:
 ******************************************************************************/
String getMsgContent(String buff){
  //+CMT: "+923001234567","","22/05/20,11:59:15+20"
  //Hello  
  unsigned int index, index2;
  index = buff.lastIndexOf("\"");
  index2 = buff.length();
  String command = buff.substring(index+1, index2);
  command.trim();
  command.toLowerCase();
  //Serial.print("index+1= "); Serial.println(index+1);
  //Serial.print("index2= "); Serial.println(index2);
  //Serial.print("length= "); Serial.println(msg.length());
  Serial.println("Command:"+command);
  return command;
}
/*******************************************************************************
 * getNumber function:
 ******************************************************************************/
String getNumber(String text){
  //r=+923001234567
  String temp = text.substring(3, 17);    //17 statt 16, weil 14-stellige Telefonnummer
  //Serial.println(temp);
  temp.trim();
  return temp;
}


/*******************************************************************************
 * controlRelayGSM function:
 ******************************************************************************/
void controlRelayGSM(int relay_no, int relay_pin, boolean status, String caller_id){
  digitalWrite(relay_pin, status);
  EEPROM.update(totalMemory+relay_no,status);
  String text = (status)? "OFF" : "ON";
  text = "Relay "+String(relay_no)+" is " +text;
  Serial.println(text);
  Reply(text, caller_id);
}

/*******************************************************************************
 * sendStatus function:
 ******************************************************************************/
void sendStatus(int relay_no, boolean status, String caller_id){
  String text = (status)? "OFF" : "ON";
  text = "Relay "+String(relay_no)+" is " +text;
  Serial.println(text);
  Reply(text, caller_id);
}

/*******************************************************************************
 * Reply function
 * Send an sms
 ******************************************************************************/
void Reply(String text, String caller_id)
{
  //return;
    sim800.print("AT+CMGF=1\r");
    delay(1000);
    sim800.print("AT+CMGS=\""+caller_id+"\"\r");
    delay(1000);
    sim800.print(text);
    delay(100);
    sim800.write(0x1A); //ascii code for ctrl-26 //sim800.println((char)26); //ascii code for ctrl-26
    delay(1000);
    Serial.println("SMS Sent Successfully.");
}
/*******************************************************************************
 * writeToEEPROM function:
 * Store registered phone numbers in EEPROM
 ******************************************************************************/
void writeToEEPROM(int addrOffset, const String &strToWrite)
{
  //byte phoneLength = strToWrite.length();
  //EEPROM.write(addrOffset, phoneLength);
  for (int i = 0; i < phoneLength; i++)
    { EEPROM.write(addrOffset + i, strToWrite[i]); }
}

/*******************************************************************************
 * readFromEEPROM function:
 * Store phone numbers in EEPROM
 ******************************************************************************/
String readFromEEPROM(int addrOffset)
{
  //byte phoneLength = strToWrite.length();
  char data[phoneLength + 1];
  for (int i = 0; i < phoneLength; i++)
    { data[i] = EEPROM.read(addrOffset + i); }
  data[phoneLength] = '\0';
  return String(data);
}

/*******************************************************************************
 * comparePhone function:
 * compare phone numbers stored in EEPROM
 ******************************************************************************/
boolean comparePhone(String number)
{
  boolean flag = 0;
  String tempPhone = "";
  //--------------------------------------------------
  for (int i = 0; i < totalPhoneNo; i++){
    tempPhone = readFromEEPROM(offsetPhone[i]);
    if(tempPhone.equals(number)){
      flag = 1;
      break;
    }
  }
  //--------------------------------------------------
  return flag;
}

void LoadStateEEPROM()
{
  STATE_RELAY_1 = EEPROM.read(totalMemory+1); delay(200);
  STATE_RELAY_2 = EEPROM.read(totalMemory+2); delay(200);
  STATE_RELAY_3 = EEPROM.read(totalMemory+3); delay(200);
  STATE_RELAY_4 = EEPROM.read(totalMemory+4); delay(200);
  
  digitalWrite(RELAY_1, STATE_RELAY_1);
  digitalWrite(RELAY_2, STATE_RELAY_2);
  digitalWrite(RELAY_3, STATE_RELAY_3);
  digitalWrite(RELAY_4, STATE_RELAY_4);
}  

```Links ist die Liste unvollständig. Rechts zeigt die vollständige Liste. Auch die SMS sehen so aus.
![Falle-Ard-Monitor|690x351](upload://rz0Z5Ed6sZ3zcFujwqS4pENCMxZ.png)

700 Byte sind nicht viel. und währen der Ausführung des Programms braucht es noch mehr RAM, das hier nicht aufgeführt ist.
Vor allem wenn man kräftig mit Serial.print("") RAM verschwendet.
Füge mal überall wo text gedruckt wird das F-Makro hinzu.
zB wird aus

Serial.println("Faild! Resetting the Module");

dann

Serial.println(F("Faild! Resetting the Module"));

Das spart zB in diesem Fall schon 27 Byte.

also überall wo mit .print bzw ,println ein Text ausgegeben wird das F() Makro hinzu.
Grüße Uwe

1 Like

DATEI - VOREINSTELLUNGEN
grafik

Ergebnis:

/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino:241:2: warning: "/*" within comment [-Wcomment]
  /* Interrupt Abfrage PIR
   
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino: In function 'boolean getResponse(String, unsigned int, boolean)':
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino:83:11: warning: unused variable 'flag' [-Wunused-variable]
   boolean flag = false;
           ^~~~
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino: In function 'boolean tryATcommand(String, String, int, int)':
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino:128:1: warning: no return statement in function returning non-void [-Wreturn-type]
 }
 ^
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino: In function 'boolean resetSIM800()':
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino:150:1: warning: no return statement in function returning non-void [-Wreturn-type]
 }
 ^
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino: In function 'void SMS_Time()':
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino:354:37: warning: variable 'index2' set but not used [-Wunused-but-set-variable]
                 unsigned int index, index2;
                                     ^~~~~~
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino: In function 'void doAction(String, String)':
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino:441:17: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     if(duration > OneMinute){
        ~~~~~~~~~^~~~~~~~~~~
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino:442:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
       if(duration > TwentyFourHours)
          ~~~~~~~~~^~~~~~~~~~~~~~~~~
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino:473:17: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     if(duration > OneMinute){
        ~~~~~~~~~^~~~~~~~~~~
/tmp/arduino_modified_sketch_432766/sketch_apr22a.ino:474:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
       if(duration > TwentyFourHours)
          ~~~~~~~~~^~~~~~~~~~~~~~~~~

Beseitge mal alles, was da steht und dann versuchs mal erneut

Das sieht bei mir aber ganz anders aus, wenn ich den Sketch kompiliere.

Der Sketch verwendet 14910 Bytes (46%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
Globale Variablen verwenden 1278 Bytes (62%) des dynamischen Speichers, 770 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Das ist der Stand, mit Deinem unbereinigten Sketch aus #4
Ich habe auf einem UNO ca. 1500 Bytes mehr Platz im Programmspeicher

Mit welcher IDE und für welches Board kompilierst Du das?

Naja,
Der Speicher für die c-strings ist durchaus in den 1342 Bytes schon drin!

Aber ja!
Mit F() kann man von den 1342 Bytes sicher viel freiräumen.

Gefährlicher scheint mir die extensive Nutzung von String zu sein.

Hier frage ich mich wofür das delay gut sein mag....
Damit sich das EEPRM zwischen den Zugriffen abkühlen kann?

Da der Sketch selber genauso groß ist, liegt das wohl am Bootloader. Da hat ein UNO einen besseren (kleineren) als z.B. ein Nano mit Old Bootloader.

Aber Probleme hängen eher am RAM, wie @uwefed und @combie schon angemerkt haben.

Der Unterschied zwischen alten und neuen Bootloader sind 512 byte (1k bzw 512 byte). Daran kann der Unterschied von 1500 byte Flash nicht liegen.
Außerdem haben einige NANOs auch asiatischer Herkunft auch den neunen Bootloader drauf.
Grüße Uwe

Richtig!
Genau genommen hängt es an den fuse-Einstellungen, wieviel Flash für den Bootloader reserviert sind. Da gibt es je nach Board beide Werte für den freien Speicher:
30720 Bytes
32256 Bytes

Aber, wie gesagt, das ist hier nicht das Problem.
Ob es reicht, alls konstanten Texte per F() aus dem RAM zu nehmen?
Oder muss man die vielen String - Objekte anfassen?

Wie groß ist eigentlich die Telefonnummmern-Liste im EEPROM?

Waren das nicht 256 Worte, vs. 1024 Worte?
Denn der Programmspeicher ist wortweise organisiert, nicht Byteweise.

Wobei die Arduinohelden bei dem Umbau von Alt nach Neu Bootloader ernsthaften Mist gebaut haben.
Denn selbst der kleinere Bootloader bringt keinen Speichervorteil, da die Fuses falsch gesetzt werden/wurden

Siehe dazu auch:

Nicht bei den Nanos.
Eben wegen dem HeldenError

Es sind fünf 14-stellige Telefonnummern. Falls weniger eingetragen sind, erfolgt jeweils ˋEmpty´.

Das und die Verwendung von '.' anstelle von "." bringt:

Der Sketch verwendet 15952 Bytes (49%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
Globale Variablen verwenden 1039 Bytes (50%) des dynamischen Speichers, 1009 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Allerdings sind die ganzen Stringkonstrukte weiterhin eine Achillesferse.

Ich habe einige serial.println Anweisungen mit dem F-Macro versehen und auch einige aus dem Sketch genommen. Damit läuft der Sketch fehlerfrei, wenn ich die include-Dateien RTCLib und Wire einbinde.
Vielen Dank für den nützlichen Hinweis.
Da ich den Sketch noch erweitern möchte (Zeitfunktionen, Interrupt aus RTCLib), wüßte ich gerne, wodrauf ich achten muss, damit der Sketch fehlerfrei läuft.
Gruß Karl

Wurde doch schon erwähnt. Vermeide Strings. Nutze statt dessen Char Arrays.

Habe ich soweit behoben. Mit weniger serial.Print Anweisungen kann ich die RTCLib einbinden und der Sketch läuft.
Gebe ich einen Befehl z.B. setAlarm1 ein, stürzt der Sketch ab.

Ich hatte grad den Sketch hier zu gemacht, da Du Dich nicht weiter geäussert hattest, ob meine mit Deinen Angaben stimmen...

Was ist setAlarm1 ???
In Deinem Code sehe ich das nicht.
Wie sieht der Code also jetzt aus?

Weniger ist gar nicht so das Problem, solange noch Progmem da ist. ...

Dein ganzes String Gewussel donnert dir den Heap voll und das kollidiert.