Creating a "Alarmlist"

Hey friends. Since i am still learning i wanted to discuss with you the way to create a proper "alarmlist"

To be more specific. I am using a Nextion and an ESP32. Lets say i measure some stuff and when something happens an errormassages should be written und displayed on a site of my Nextion.

Since my code isnt finished, my question is more of software-engineering nature.

My idea and code so far:

Lets say i have 3 events that gives me 3 different errormessages : Event 1: "Errormassage 1" Event 2: "Errormassage 2" Event 3: "Errormassage 3"

Idea 1: I store the massages that accur in a char-array: char *errorMsgs[4][100]; f.e:

void datalogOnOffPopCallback(void *ptr)
{
  uint32_t t_datalogState;
  datalogOnOff.getValueDS("Datenlogging",&t_datalogState);
  if(t_datalogState==1)
  {
    errorMsgs[2][100] = {"Errormassage 2"};
  }
  else{errorMsgs[2][100] = '\0';}
}

So when the button is pushed down, the errormassage 2 will be stored into the array . When its not it should be emtpy.

My first question now: Is this the best way to store strings? I mean, i am pretty sure there are more elegant ways to do so, but my question is more, if i am doing something significant wrong with this idea?

To make the first post not to big i will stop here and continue afterwards it is clear if my idea is ok

Why not simply put the error messages in an array and use the error number as an index to the appropriate one

const char * errorMessages[] = {"Message 1", "Message 2", "Message 3"};

void setup()
{
  Serial.begin(115200);
  for (int errorNumber = 0; errorNumber < 3; errorNumber++)
  {
    printErrorMessage(errorNumber);
  }
}

void loop()
{
}

void printErrorMessage(int number)
{
  Serial.println(errorMessages[number]);
}

If you are short of memory then you can put the error strings in PROGMEM

hello

hmm. my idea was to fill a "list" (my char array) with current errormassges. So if only 2 errormassages are relevant right now, only these 2 should be written.

So how i see it.your idea would always be listing all errormessages (doesnt matter if they are relevant now or not)

or do is miss something?

My idea is following:

I have this lists of errormassges:

char *errorMsgs[5][200];

errorMsgs[0][100] = {"Errormassage 1"};
errorMsgs[1][100] = {"Errormassage 2"};
errorMsgs[2][100] = {"Errormassage 3"};

This is my list. And this list should be dynamicly be filled with the messages or not, depending if an event is happening or not. So it could also look like this:

char *errorMsgs[5][200];

errorMsgs[0][100] = {"Errormassage 1"};
errorMsgs[1][100] = {""};
errorMsgs[2][100] = {"Errormassage 3"};

To read it into my Nextion site, i created a function something like this:

void alarmlistPopCallback(void *ptr)
{
  int z = 1;
  
  for (int i= 0; i < 3; i++)            
    {
      if(errorMsgs[i][100]!='\0')
      {
      String str = String("ErrorMsg_")+String(z)+String(".txt=")+String("\"")+String(errorMsgs[i][100])+String("\"");
      Serial.println(str);
      Serial2.print(str);
      Serial2.write(0xFF);
      Serial2.write(0xFF);
      Serial2.write(0xFF);
      z++;
      delay(500);
      }
    }
}

Its iterates through the char array and checks if the specific index of thr array is filled or not. When it is filled, it will be written into the specific textfield.

I hope it is somehow clear what i mean.

Any input?

Thank you

Now I have a better idea of what you want to do.

Suppose that you have a total of say 100 possible error messages of which 10 may be active at any one time having been written into an array of current error messages. Your program will need to be able to contain 110 error messages, 100 in the code and 10 in the current list. If you just use a single array and access the messages directly the program only has to contain 100 messages and there will be no overhead copying them around from place to place

ok thank you for your answer.

I have an understandnig question. Maybe its a stupid question :confused:

But when i have ma char array and its filled like this

errorMsgs[0][100] = {"Errormassage 1"}; errorMsgs[1][100] = {""}; errorMsgs[2][100] = {"Errormassage 3"}; errorMsgs[3][100] = {"This is a test"}; errorMsgs[4][100] = {"Hello"};

and i want to empty the complete array. So that nothing is written in it and can be filled from new Whats the best whay to do so

Thank you

If you are determined to put a new set of error messages in the array then why bother to "empty" it ? Simply put the new ones in. You will presumably only be accessing valid elements of the array although the array will need to be able to hold the maximum number of entries anticipated.

i want to delete them because i check in this function

void alarmlistPopCallback(void *ptr)
{
  int z = 1;
 
  for (int i= 0; i < 3; i++)           
    {
      if(errorMsgs[i][100]!='\0')
      {
      String str = String("ErrorMsg_")+String(z)+String(".txt=")+String("\"")+String(errorMsgs[i][100])+String("\"");
      Serial.println(str);
      Serial2.print(str);
      Serial2.write(0xFF);
      Serial2.write(0xFF);
      Serial2.write(0xFF);
      z++;
      delay(500);
      }
    }
}

if the specific index of the array is empty or not. I need it because i only wanted to list messages that are currently “relevrant”

thank you

I feel that I am working in the dark here, so some questions

Do you have a full list of the error messages ? How many are there ? How do you know which ones are relevant to the current situation ? How is the current situation identified, by name, number, something else ?

ok sorry. i will try it better

So like i mentioned it at the beginnig. Its right now some kind of “work in progress”. Becauce alone i am unable to reach the goal.

Do you have a full list of the error messages ?

Not yet. But my idea was, when i can manage it with three messages, i can add more and more if needed

How many are there ?
At the the end, they will be maybe 10 alarms

How do you know which ones are relevant to the current situation ?
This depends on the alarm. For example. I am measuring the ph-value. If the ph-value reaches a specific limit, an errormessages + a timespamp should be written into a list. here is my first example

void Alarms()
{ 
  if(init_1._alarmState==1)
  {
    if(A1.input<strtof((init_1._lowerAlarm).c_str(),0))
    {
      Serial2.print("alert.picc=26");Serial2.write(0xFF);Serial2.write(0xFF);Serial2.write(0xFF);
      errorMsgs[0][100] = {"Lower limit violated"};
      //sprintf(errorMsgsTimestamp[0][49], "%02d.%02d.%02d",now.day(),now.month(),now.year());
      //currentTimeStamp(0);
      
    }
    else if(A1.input > strtof((init_1._upperAlarm).c_str(),0))
    {
      Serial2.print("alert.picc=26");Serial2.write(0xFF);Serial2.write(0xFF);Serial2.write(0xFF);
      errorMsgs[1][100] = {"upper limit violated"};
    }
    else{Serial2.print("alert.picc=25");Serial2.write(0xFF);Serial2.write(0xFF);Serial2.write(0xFF);errorMsgs[0][100] = '\0';}
  }

  else{Serial2.print("alert.picc=25");Serial2.write(0xFF);Serial2.write(0xFF);Serial2.write(0xFF);errorMsgs[0][100] = '\0';}
}

So my idea was to write and store the errormessages into my char array >errorMsgs< (timespamp will follow later).

Now i have either “upper limit violated” in adress errorMsgs[1][100] or “Lower limit violated” in adress errorMsgs[0][100].

Do you know until here what my plans are?

Sorry for the circumstances, but thank you

I think that you are making this too complicated

Put the 10 error messages in an array of char pointers

Now, let’s say that you are measuring pH and the required value is exceeded then print the relevant message from the array by using the index to it. Similarly if the value is below that required then print that error message instead using the index.

Actually I don’t see the need for an array at all unless you want to use PROGMEM to save RAM. Why not simply print the relevant error message using the F() macro ?

if (pHValue < lowerLimit)
  {
    Serial.println(F("Ph below target"));
  }

Of course you could send any control characters and timestamp required by calling a function to do it to avoid code repetition. You could also print the entire error message, control characters and timestamp from a function by passing the error text to a function

What advantages do you envisage by copying error messages from one array to another ?

The problem that i have ( and thats was the reason, or at least was it my plan) is to list the messages in my Nextion device correctly. I dont know how familiar you are with Nextion, but i have manly 2 options: 1 Textfield for all messages (imo hard to handle the formating) or make 10 Textfield for my 10 errormessages.

Lets say i do it like you have recommend it:

const char * errorMessages[] = {"Upper limit reached", "lower limit reached", "another error"};

The first problem (where i fail) is to know, do i take 1 Textfield or 1 textfield for each messages.

Lets say: "upper limit reached" appears first --> write into Textfield_1 Then "another error" gets also relevant ---> write tinto Textfield_2

But what happens when "another error" appears first. Than it should be written into Textfield_1

Thats where my idea of an char array comes from

So the first errormessages that appears should be at the top of my errorlist the second on the second and so on.

Do you know what i mean?

I know little or nothing about Nextion but a display device that will not let you put the text that you want where you want it would be useless. Surely you can decide what text appears and where and change that text whilst the program is running

What is hard about formatting an error message to be displayed in a Nextion text field ? Are you worried about centering it, the font size, font colour or what ?

Maybe i found some kind of solution. When it works i will post it.

But stuck with this problem:

char *test22[3];
char dateStamp[13];
DateTime now = rtc.now();

sprintf(dateStamp, "%02d.%02d.%02d",now.day(),now.month(),now.year());

Is it possible to store the value of dateStamp in test22[0]?

Until now i fail to do so

Manuel_o: Is it possible to store the value of dateStamp in test22[0]?

Yes and no.

You could do this:

char *test22[3];
char dateStamp[13];
DateTime now = rtc.now();

sprintf(dateStamp, "%02d.%02d.%02d",now.day(),now.month(),now.year());
test22[0]=dateStamp;
Serial.println(test22[0]);

But that's really just pointing test22[0] to the memory you declared for datestamp and if it goes out of scope, your pointer will now be pointing to garbage. If you want a copy of datestamp, you must set some memory aside for it.

Sorry to bother you all the whole time. but i realy try to solve this puzzle

i have globaly declared

char *errorMsgs[5][200];
char *errorMsgsTimestamp[5][50];

Now i try to store “things” in it:

void Alarms()
{ 
    DateTime now = rtc.now();

    char dateStamp[13];

    sprintf(dateStamp, "%02d",now.day());
    if(A1.input<strtof((init_1._lowerAlarm).c_str(),0))
    {
      Serial2.print("alert.picc=26");Serial2.write(0xFF);Serial2.write(0xFF);Serial2.write(0xFF);
      char* string="test string"; 

      errorMsgs[0][100] = {string};
      errorMsgsTimestamp[0][49]=dateStamp;
}
      
    }

Now with this function i disyplay the values to my Nextion

void alarmlistPopCallback(void *ptr)
{
  int z = 1;
  
  for (int i= 0; i < 3; i++)            
    {
      if(errorMsgs[i][100]!='\0')
      {
      String str = String("ErrorMsg_")+String(z)+String(".txt=")+String("\"")+String(errorMsgs[i][100])+String("\"");
      Serial.println(str);
      Serial2.print(str);
      Serial2.write(0xFF);
      Serial2.write(0xFF);
      Serial2.write(0xFF);

      String str_2 = String("Timestamp_")+String(z)+String(".txt=")+String("\"")+String(errorMsgsTimestamp[0][49])+String("\"");
      Serial.println(str_2);
      Serial2.print(str_2);
      Serial2.write(0xFF);
      Serial2.write(0xFF);
      Serial2.write(0xFF);
      z++;
      delay(100);
      }
    }
}

The outcome is: errorMsgs[0][100] is written into my textfield ErrorMsg_1 perfectly
but errorMsgsTimestamp[0][49] isnt written into my textfield Timestamp_1.
it shows something like wired characters, points and pixels. wired.

What is my mistake?

Again. Thanks

Don't make an array of pointers, a 2D array of char will do:

char errorMsgs[5][200];
void setup()
{
Serial.begin(115200);
char dateStamp[13];

sprintf(dateStamp, "%02d.%02d.%02d",14,11,2019);
strcpy(errorMsgs[0],dateStamp);
strcpy(errorMsgs[1],"Hello world");
Serial.println(errorMsgs[0]);
Serial.println(errorMsgs[1]);
}

void loop()
{
}

So. I am kinda finished with the fundament of an alarmlist.
I will post my code here. Maybe it will help someone, and maybe someone has arguemnets how to improve the code

Simple code that produces an alarm ->errormessages:

void Alarms()
{ 
  if(init_1._alarmState==1)
  {
    if(A1.input<strtof((init_1._lowerAlarm).c_str(),0))
    {
      Serial2.print("alert.picc=26");Serial2.write(0xFF);Serial2.write(0xFF);Serial2.write(0xFF); 
      strcpy(errorMsgs[0],"lower limit violated");
      strcpy(errorMsgsTimestamp[0],getTimestamp());
    }
    else if(A1.input > strtof((init_1._upperAlarm).c_str(),0))
    {
      Serial2.print("alert.picc=26");Serial2.write(0xFF);Serial2.write(0xFF);Serial2.write(0xFF);
      strcpy(errorMsgs[0],"upper limit violated");
      strcpy(errorMsgsTimestamp[0],getTimestamp());
    }
    else{Serial2.print("alert.picc=25");Serial2.write(0xFF);Serial2.write(0xFF);Serial2.write(0xFF);}
  }
  else{Serial2.print("alert.picc=25");Serial2.write(0xFF);Serial2.write(0xFF);Serial2.write(0xFF);}
}

Code that writes the errormessages into given textfields on the Nextion:

void alarmlistPopCallback(void *ptr)
{
  int z = 1;
  for (int i= 0; i < 3; i++)            
    {
      if(errorMsgs[0]!='\0')
      {
      String str = String("ErrorMsg_")+String(z)+String(".txt=")+String("\"")+String(errorMsgs[i])+String("\"");
      Serial.println(str);
      Serial2.print(str);
      Serial2.write(0xFF);
      Serial2.write(0xFF);
      Serial2.write(0xFF);

      String str_2 = String("Timestamp_")+String(z)+String(".txt=")+String("\"")+String(errorMsgsTimestamp[i])+String("\"");
      Serial.println(str_2);
      Serial2.print(str_2);
      Serial2.write(0xFF);
      Serial2.write(0xFF);
      Serial2.write(0xFF);
      z++;
      delay(100);
      }
    }
}

Where i am still struggle: I wanna create a function, that gives me a timestamp:

char getTimestamp()
{
  DateTime now = rtc.now();
  char dateStamp[22];
  sprintf(dateStamp, "%02d.%02d.%02d\r\n%02d:%02d:%02d",now.day(),now.month(),now.year(),now.hour(), now.minute(),now.second());
  return dateStamp;
}

I know the function is wrong. I dont wanna create a memoryleak. I am still studying how to create a proper function that creates a correct char-return-value. How would you make such a function?

best regards

Any help with my function? still struggling :confused:

Here you go:

void setup()
{
  Serial.begin(115200);
  char buffer[22];
  getTimestamp(buffer,22);
  Serial.println(buffer);
}

void loop()
{
}

void getTimestamp(char * buf,byte len)
{
//  DateTime now = rtc.now();
  snprintf(buf,len, "%02d.%02d.%02d\r\n%02d:%02d:%02d",19,11,19,6,55,21);
}

The arduino I have hooked up for testing doesn’t have a RTC, so I used constants. You can obviously hook it up to use the clock as your original does.

It might also be convenient to have the function return a char* and return buf.