Code only responds once.

Hi.

I made a program to remotely read the temperature at my sommerplace, and then send it back to me via SMS.

This works great… once.

It starts up as it is supposed to and responds with the temperatures when I send it #t.
But when I try send #t a second time, it responds with an empty SMS.

It does not respond with anything else than an empty SMS until I reset it, the it behaves as it should … once.

I can’t figgure out why it is doing this.

This is the GSM shield I’m using:

These are the temperature sensors:

This is the code I’m working with:

#include <SoftwareSerial.h> 
#include <OneWire.h>
#include <DallasTemperature.h>
SoftwareSerial SIM900(2, 3);

#define ONE_WIRE_BUS 5

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

DeviceAddress Temp_Ute = { 0x28, 0xFF, 0x51, 0x9F, 0x63, 0x15, 0x03, 0xDB };
DeviceAddress Temp_Bad = { 0x28, 0xFF, 0x85, 0xA0, 0x63, 0x15, 0x03, 0x48 };
DeviceAddress Temp_Kjokken = { 0x28, 0xFF, 0xAE, 0x73, 0x63, 0x15, 0x02, 0x17 };
DeviceAddress Temp_Stue = { 0x28, 0xFF, 0x19, 0x73, 0x63, 0x15, 0x02, 0x09 };
DeviceAddress Temp_Ekstra = { 0x28, 0xFF, 0xDD, 0x86, 0x63, 0x15, 0x01, 0x26 };

char inchar;
String sendSMSContent[50];
String tempStatus;
double tempUte,tempBad,tempKjokken,tempStue,tempEkstra;

void setup()
{
  SIM900power();// wake up the GSM shield
  
  sensors.begin();
  
  sensors.setResolution(Temp_Ute, 10);
  sensors.setResolution(Temp_Bad, 10);
  sensors.setResolution(Temp_Kjokken, 10);
  sensors.setResolution(Temp_Stue, 10);
  sensors.setResolution(Temp_Ekstra, 10 );
  
  SIM900.begin(19200);
  delay(10000); // give time to log on to network.
  SIM900.print("AT+CMGF=1\r");  // set SMS mode to text
  delay(100);
  SIM900.print("AT+CNMI=2,2,0,0,0\r"); 
  
  sendSMS("GSM shield ready");
  delay(5000);
  sendSMS("Thermometers ready"); 
}

void SIM900power()
// software equivalent of pressing the GSM shield "power" button
{
  digitalWrite(9, HIGH);
  delay(1000);
  digitalWrite(9, LOW);
  delay(7000);
}

void loop() 
{
  if(SIM900.available() >0)
  {
    inchar=SIM900.read(); 
    if (inchar=='#')
    {
      delay(10);
 
      inchar=SIM900.read(); 
      if (inchar=='t')
      {
        getAndSendTemp();
        delay(10);
        SIM900.println("AT+CMGD=1,4"); // delete all SMS
      }
    }
  }
}

void sendSMS(String sendSMSContent)
{
  SIM900.print("AT+CMGF=1\r");// AT command to send SMS message
  delay(100);
  SIM900.println("AT + CMGS = \"+0000000000\"");// recipient's mobile number, in international format
  delay(100);
  SIM900.println(sendSMSContent);// message to send
  delay(100);
  SIM900.println((char)26);// End AT command with a ^Z, ASCII code 26
  delay(100); 
  SIM900.println();
}


void getAndSendTemp()
{ 
 sensors.requestTemperatures();
 tempUte = sensors.getTempC(Temp_Ute);
 tempBad = sensors.getTempC(Temp_Bad);
 tempKjokken = sensors.getTempC(Temp_Kjokken);
 tempStue = sensors.getTempC(Temp_Stue);
 tempEkstra = sensors.getTempC(Temp_Ekstra);
 
 String stringTempUte = String(tempUte);
 String stringTempBad = String(tempBad);
 String stringTempKjokken = String(tempKjokken);
 String stringTempStue = String(tempStue);
 String stringTempEkstra = String(tempEkstra);
 
 tempStatus.concat("Temp ute:          " + stringTempUte + " C\n");
 tempStatus.concat("Temp bad:         " + stringTempBad + " C\n" );
 tempStatus.concat("Temp kjokken:  " + stringTempKjokken + " C\n");
 tempStatus.concat("Temp stue:        " + stringTempStue + " C\n");
 tempStatus.concat("Temp ekstra:     " + stringTempEkstra + " C");
 
 sendSMS(tempStatus); 
}

Is there something I missed or have done wrong?

Thanks in advance!

I wonder if any other characters are received along with #t - for example a carriage return or line feed - or both. For debugging, at least, print out all the characters that are received.

If you need two characters why not use if (Serial.available() >= 2) {

Have a look at Serial Input Basics for a more general way to receive data reliably.

...R

Robin2: I wonder if any other characters are received along with #t - for example a carriage return or line feed - or both. For debugging, at least, print out all the characters that are received.

If you need two characters why not use if (Serial.available() >= 2) {

Have a look at Serial Input Basics for a more general way to receive data reliably.

...R

that could be the case, but I have used the same "system" to read and control 8 relays on a RELAY8 board through I2C. There I do not have the issue where the board only responds once.

Here is the loop of the code I'm talking about

void loop() 
{
  if(SIM900.available() >0)
  {
    inchar=SIM900.read(); 
    if (inchar=='#')
    {
      delay(10);

      inchar=SIM900.read(); 
      if (inchar=='r')
      {
        
        delay(10);
        inchar=SIM900.read();
        if (inchar=='0'){
        sendSMS("All relays are off");
        delay(5000);
        sendValueToLatch(relayPort);}
        delay(10);
        
        if (inchar=='1'){
        sendSMS("Flipping relay 1");
        sendValueToLatch(B1);
        delay(5000);
        relayState();}
        delay(10);
          
        if (inchar=='2'){
        sendSMS("Flipping relay 2");
        sendValueToLatch(B10);
        delay(5000);
        relayState();}
        delay(10);
         
        if (inchar=='3'){
        sendSMS("Flipping relay 3");
        sendValueToLatch(B100);
        delay(5000);
        relayState();}
        delay(10);
        
        if (inchar=='4'){
        sendSMS("Flipping relay 4");
        sendValueToLatch(B1000);
        delay(5000);
        relayState();}
        delay(10);
        
        if (inchar=='5'){
        sendSMS("Flipping relay 5");
        sendValueToLatch(B10000);
        delay(5000);
        relayState();}
        delay(10);
        
        if (inchar=='6'){
        sendSMS("Flipping relay 6");
        sendValueToLatch(B100000);
        delay(5000);
        relayState();}
        delay(10);  
        
        if (inchar=='7'){
        sendSMS("Flipping relay 7");
        sendValueToLatch(B1000000);
        delay(5000);
        relayState();}
        delay(10);
        
        if (inchar=='8'){
        sendSMS("Flipping relay 8");
        sendValueToLatch(B10000000);
        delay(5000);
        relayState();}
        delay(10);
        
        if (inchar=='9'){
        relayState();}
        
        delay(10);
        
        SIM900.println("AT+CMGD=1,4"); // delete all SMS
      }
    }
  }
}

I have heard from some people that all those Strings fill up the RAM very quickly and then the board will start acting up. I plan to combine the relay control and the temperature sensor program, do you think I will run into RAM issues there? Should I consider getting the Arduino Zero, which has 32KB of SRAM?

Friisern: Should I consider getting the Arduino Zero, which has 32KB of SRAM?

Wouldn't it be cheaper, simpler and more professional not to use Strings. Serial Input Basics does not use Strings.

You need to post the complete program that works if you want us to analyze the differences.

...R

Robin2:
Wouldn’t it be cheaper, simpler and more professional not to use Strings. Serial Input Basics does not use Strings.

You need to post the complete program that works if you want us to analyze the differences.

…R

Relaycontrol code:

#include <SoftwareSerial.h> 
#include "Wire.h"
SoftwareSerial SIM900(2, 3);
 
#define I2C_ADDR 0x20 // 0x20 is the address with all jumpers removed
byte relayPort=B0;


char inchar;
String sendSMSContent[50];

char all[200],one[30];

 
void setup()
{
  SIM900power();// wake up the GSM shield
  Serial.begin(19200);
  Serial.println("GSM shield booting");
  Serial.println("Relay8 shield booting");
  
  Wire.begin(); // Wake up I2C bus
  
  SIM900.begin(19200);
  delay(5000);
  //delay(20000);  // give time to log on to network.
  SIM900.print("AT+CMGF=1\r");  // set SMS mode to text
  delay(100);
  SIM900.print("AT+CNMI=2,2,0,0,0\r"); 
  delay(100);
  
  
  Wire.beginTransmission(I2C_ADDR);  // Set addressing style
  Wire.write(0x12);
  Wire.write(0x20); // use table 1.4 addressing
  Wire.endTransmission();
  sendValueToLatch(relayPort); // relay 6 defaults to on on my shield. This forces it off at boot.
  // Set I/O bank A to outputs
  Wire.beginTransmission(I2C_ADDR);
  Wire.write(0x00); // IODIRA register
  Wire.write(0x00); // Set all of bank A to outputs
  Wire.endTransmission();
  
  delay(5000);
  
  Serial.println("GSM shield ready");
  Serial.println("Relay8 shield ready.");
  
  sendSMS("GSM shield ready");
  delay(5000);
  sendSMS("Relay8 shield ready.");
  
}

 
void SIM900power()
// software equivalent of pressing the GSM shield "power" button
{
  digitalWrite(9, HIGH);
  delay(1000);
  digitalWrite(9, LOW);
  delay(7000);
}

 
void loop() 
{
  if(SIM900.available() >0)
  {
    inchar=SIM900.read(); 
    if (inchar=='#')
    {
      delay(10);
 
      inchar=SIM900.read(); 
      if (inchar=='r')
      {
        
        delay(10);
        inchar=SIM900.read();
        if (inchar=='0'){
        sendSMS("All relays are off");
        delay(5000);
        sendValueToLatch(relayPort);}
        delay(10);
        
        if (inchar=='1'){
        sendSMS("Flipping relay 1");
        sendValueToLatch(B1);
        delay(5000);
        relayState();}
        delay(10);
          
        if (inchar=='2'){
        sendSMS("Flipping relay 2");
        sendValueToLatch(B10);
        delay(5000);
        relayState();}
        delay(10);
         
        if (inchar=='3'){
        sendSMS("Flipping relay 3");
        sendValueToLatch(B100);
        delay(5000);
        relayState();}
        delay(10);
        
        if (inchar=='4'){
        sendSMS("Flipping relay 4");
        sendValueToLatch(B1000);
        delay(5000);
        relayState();}
        delay(10);
        
        if (inchar=='5'){
        sendSMS("Flipping relay 5");
        sendValueToLatch(B10000);
        delay(5000);
        relayState();}
        delay(10);
        
        if (inchar=='6'){
        sendSMS("Flipping relay 6");
        sendValueToLatch(B100000);
        delay(5000);
        relayState();}
        delay(10);  
        
        if (inchar=='7'){
        sendSMS("Flipping relay 7");
        sendValueToLatch(B1000000);
        delay(5000);
        relayState();}
        delay(10);
        
        if (inchar=='8'){
        sendSMS("Flipping relay 8");
        sendValueToLatch(B10000000);
        delay(5000);
        relayState();}
        delay(10);
        
        if (inchar=='9'){
        relayState();}
        
        delay(10);
        
        SIM900.println("AT+CMGD=1,4"); // delete all SMS
      }
    }
  }
}


void sendSMS(String sendSMSContent)
{
  SIM900.print("AT+CMGF=1\r");// AT command to send SMS message
  delay(100);
  SIM900.println("AT + CMGS = \"+0000000000\"");// recipient's mobile number, in international format
  delay(100);
  SIM900.println(sendSMSContent);// message to send
  delay(100);
  SIM900.println((char)26);// End AT command with a ^Z, ASCII code 26
  delay(100); 
  SIM900.println();
}


void sendValueToLatch(int latchValue)
{
  relayPort=relayPort^latchValue; //XOR toggles desired port
  Wire.beginTransmission(I2C_ADDR);
  Wire.write(0x12); // Select GPIOA
  Wire.write(relayPort); // Send value to bank A
  relayState();
  Wire.endTransmission();
}


void relayState() 
{
  all[0] = 0; // Init a zero length null-terminated string
  
  for (int i = 1;i < 9;i++)
  {
    if (i) // add a space if this is not the first relay
      strcat(all," ");

    // format report for one relay
    sprintf(one,"Relay %d is %s.\n",i,bitRead(relayPort,i-1)  ? "ON" : "OFF");
    // add it to the total
    strcat(all,one);
  }
  // send out the combined report
  sendSMS(all);
  
}

Temperature sensor code:

#include <SoftwareSerial.h> 
#include <OneWire.h>
#include <DallasTemperature.h>
SoftwareSerial SIM900(2, 3);

#define ONE_WIRE_BUS 5

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

DeviceAddress Temp_Ute = { 0x28, 0xFF, 0x51, 0x9F, 0x63, 0x15, 0x03, 0xDB };
DeviceAddress Temp_Bad = { 0x28, 0xFF, 0x85, 0xA0, 0x63, 0x15, 0x03, 0x48 };
DeviceAddress Temp_Kjokken = { 0x28, 0xFF, 0xAE, 0x73, 0x63, 0x15, 0x02, 0x17 };
DeviceAddress Temp_Stue = { 0x28, 0xFF, 0x19, 0x73, 0x63, 0x15, 0x02, 0x09 };
DeviceAddress Temp_Ekstra = { 0x28, 0xFF, 0xDD, 0x86, 0x63, 0x15, 0x01, 0x26 };

char inchar;
String sendSMSContent[50];
String tempStatus;
double tempUte,tempBad,tempKjokken,tempStue,tempEkstra;

void setup()
{
  SIM900power();// wake up the GSM shield
  
  sensors.begin();
  
  sensors.setResolution(Temp_Ute, 10);
  sensors.setResolution(Temp_Bad, 10);
  sensors.setResolution(Temp_Kjokken, 10);
  sensors.setResolution(Temp_Stue, 10);
  sensors.setResolution(Temp_Ekstra, 10 );
  
  SIM900.begin(19200);
  delay(5000);
  //delay(20000);  // give time to log on to network.
  SIM900.print("AT+CMGF=1\r");  // set SMS mode to text
  delay(100);
  SIM900.print("AT+CNMI=2,2,0,0,0\r"); 
  
  sendSMS("GSM shield ready");
  delay(5000);
  sendSMS("Thermometers ready"); 
}

void SIM900power()
// software equivalent of pressing the GSM shield "power" button
{
  digitalWrite(9, HIGH);
  delay(1000);
  digitalWrite(9, LOW);
  delay(7000);
}

void loop() 
{
  if(SIM900.available() >0)
  {
    inchar=SIM900.read(); 
    if (inchar=='#')
    {
      delay(10);
 
      inchar=SIM900.read(); 
      if (inchar=='t')
      {
        getAndSendTemp();
        delay(10);
        SIM900.println("AT+CMGD=1,4"); // delete all SMS
      }
    }
  }
}

void sendSMS(String sendSMSContent)
{
  SIM900.print("AT+CMGF=1\r");// AT command to send SMS message
  delay(100);
  SIM900.println("AT + CMGS = \"+0000000000\"");// recipient's mobile number, in international format
  delay(100);
  SIM900.println(sendSMSContent);// message to send
  delay(100);
  SIM900.println((char)26);// End AT command with a ^Z, ASCII code 26
  delay(100); 
  SIM900.println();
}


void getAndSendTemp()
{ 
 sensors.requestTemperatures();
 tempUte = sensors.getTempC(Temp_Ute);
 tempBad = sensors.getTempC(Temp_Bad);
 tempKjokken = sensors.getTempC(Temp_Kjokken);
 tempStue = sensors.getTempC(Temp_Stue);
 tempEkstra = sensors.getTempC(Temp_Ekstra);
 
 String stringTempUte = String(tempUte);
 String stringTempBad = String(tempBad);
 String stringTempKjokken = String(tempKjokken);
 String stringTempStue = String(tempStue);
 String stringTempEkstra = String(tempEkstra);
 
 tempStatus.concat("Temp ute:          " + stringTempUte + " C\n");
 tempStatus.concat("Temp bad:         " + stringTempBad + " C\n" );
 tempStatus.concat("Temp kjokken:  " + stringTempKjokken + " C\n");
 tempStatus.concat("Temp stue:        " + stringTempStue + " C\n");
 tempStatus.concat("Temp ekstra:     " + stringTempEkstra + " C");
 
 sendSMS(tempStatus); 
}

I am completely open to suggestions, I’m learning as I go and would love to learn more efficient methods.

Your relay program is very poorly formatted which makes it hard to read. Have you tried the auto-format option in the IDE ?

As far as I can see your relay code sends an SMS reply immediately, whereas the sensor code waits for data from the Dallas sensor. I don't have one of those but from reading other Threads it seems that the standard library takes a long time to get a value. (Hope I am not mixing up libraries).

You can easily check if this is the problem by temporarily taking the sensor request out of the getAndSendTemp() function and just sending back a fixed value.

...R

Robin2: Your relay program is very poorly formatted which makes it hard to read. Have you tried the auto-format option in the IDE ?

I did that, but the difference was minimal. Is there some rule of thumb I have missed?

As far as I can see your relay code sends an SMS reply immediately, whereas the sensor code waits for data from the Dallas sensor. I don't have one of those but from reading other Threads it seems that the standard library takes a long time to get a value. (Hope I am not mixing up libraries).

I have taken a look at the code in the DallasTemperature library, but I could not see any obvious clues I have missed.

You can easily check if this is the problem by temporarily taking the sensor request out of the getAndSendTemp() function and just sending back a fixed value.

Good suggestion, but the same issue is still there. When I send it #t the first time, it responds with the temperature in all five zones in one SMS. Perfect. When I try to send it #t one minute later, it responds with an empty SMS.

Could it be that the values of the Strings in getAndSendTemp() collide when I send the second #t and call getAndSendTemp() again?

Thanks for taking your time with this, very thankful for that.

Friisern: IGood suggestion, but the same issue is still there. When I send it #t the first time, it responds with the temperature in all five zones in one SMS. Perfect. When I try to send it #t one minute later, it responds with an empty SMS.

Post that version of your program.

Strings can cause strange problems if they corrupt memory.

Have you tried taking a copy of the working program and stripping it down and adding the new bits into it - so that you can be very clear what line of code is causing the problem.

...R

Robin2:
Post that version of your program.

#include <SoftwareSerial.h> 
#include <OneWire.h>
#include <DallasTemperature.h>
SoftwareSerial SIM900(2, 3);

#define ONE_WIRE_BUS 5

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

DeviceAddress Temp_Ute = { 
  0x28, 0xFF, 0x51, 0x9F, 0x63, 0x15, 0x03, 0xDB };
DeviceAddress Temp_Bad = { 
  0x28, 0xFF, 0x85, 0xA0, 0x63, 0x15, 0x03, 0x48 };
DeviceAddress Temp_Kjokken = { 
  0x28, 0xFF, 0xAE, 0x73, 0x63, 0x15, 0x02, 0x17 };
DeviceAddress Temp_Stue = { 
  0x28, 0xFF, 0x19, 0x73, 0x63, 0x15, 0x02, 0x09 };
DeviceAddress Temp_Ekstra = { 
  0x28, 0xFF, 0xDD, 0x86, 0x63, 0x15, 0x01, 0x26 };

char inchar;
String sendSMSContent[50];
String tempStatus;
double tempUte,tempBad,tempKjokken,tempStue,tempEkstra;

void setup()
{
  SIM900power();// wake up the GSM shield

  sensors.begin();

  sensors.setResolution(Temp_Ute, 10);
  sensors.setResolution(Temp_Bad, 10);
  sensors.setResolution(Temp_Kjokken, 10);
  sensors.setResolution(Temp_Stue, 10);
  sensors.setResolution(Temp_Ekstra, 10 );

  SIM900.begin(19200);
  delay(5000);
  //delay(20000);  // give time to log on to network.
  SIM900.print("AT+CMGF=1\r");  // set SMS mode to text
  delay(100);
  SIM900.print("AT+CNMI=2,2,0,0,0\r"); 

  sendSMS("GSM shield ready");
  delay(5000);
  sendSMS("Thermometers ready"); 
}

void SIM900power()
// software equivalent of pressing the GSM shield "power" button
{
  digitalWrite(9, HIGH);
  delay(1000);
  digitalWrite(9, LOW);
  delay(7000);
}

void loop() 
{
  if(SIM900.available() >0)
  {
    inchar=SIM900.read(); 
    if (inchar=='#')
    {
      delay(10);

      inchar=SIM900.read(); 
      if (inchar=='t')
      {
        getAndSendTemp();
        delay(10);
        SIM900.println("AT+CMGD=1,4"); // delete all SMS
      }
    }
  }
}

void sendSMS(String sendSMSContent)
{
  SIM900.print("AT+CMGF=1\r");// AT command to send SMS message
  delay(100);
  SIM900.println("AT + CMGS = \"+4793459644\"");// recipient's mobile number, in international format
  delay(100);
  SIM900.println(sendSMSContent);// message to send
  delay(100);
  SIM900.println((char)26);// End AT command with a ^Z, ASCII code 26
  delay(100); 
  SIM900.println();
}


void getAndSendTemp()
{ 
  sensors.requestTemperatures();
  tempUte = sensors.getTempC(Temp_Ute);
  tempBad = sensors.getTempC(Temp_Bad);
  tempKjokken = sensors.getTempC(Temp_Kjokken);
  tempStue = sensors.getTempC(Temp_Stue);
  tempEkstra = sensors.getTempC(Temp_Ekstra);

  String stringTempUte = String(tempUte);
  String stringTempBad = String(tempBad);
  String stringTempKjokken = String(tempKjokken);
  String stringTempStue = String(tempStue);
  String stringTempEkstra = String(tempEkstra);

  tempStatus.concat("Temp ute:          " + stringTempUte + " C\n");
  tempStatus.concat("Temp bad:         " + stringTempBad + " C\n" );
  tempStatus.concat("Temp kjokken:  " + stringTempKjokken + " C\n");
  tempStatus.concat("Temp stue:        " + stringTempStue + " C\n");
  tempStatus.concat("Temp ekstra:     " + stringTempEkstra + " C");

  sendSMS(tempStatus); 
}

All you want each time is the five readings, right? It looks like you keep concatenating to tempStatus without emptying it. I would be curious to see what happens if you move the declaration of tempStatus into getAndSendTemp().

I also noticed there is a global definition sendSMSContent which you never use.

Referring to Reply# 8 ... As far as I can see that code still makes calls to the sensor function.

Change the function getAndSendTemp() to this, and see what happens

void getAndSendTemp() { 
  sendSMS("This is a test");
}

...R