[gelöst] Irritationen bei Stringverarbeitung

Ich versuche aus einem Array (String) bestimmte Daten auszulesen und zu verketten.

String showEventsSelected(String heute){
  String result;
  result.reserve(200);

  Serial.print("Events ab ");
  Serial.println(heute);
  for (int i = 0; i < anzEvents; i++) {
    if (trashData[i].eventStart > heute){
      Serial.print("Abfuhren am ");
      eventDate = trashData[i].eventStart;
      location = trashData[i].eventLocation;
      Serial.println(eventDate);
      break;
    }
  }
  for (int i = 0; i < anzEvents; i++) {
    if (trashData[i].eventStart == eventDate){
      Serial.println(trash[i]); // nur zum Testen
      result += trash[i];
    }
  }
  return result;
}

Als Ausgabe bekomme ich "

Events ab 20240218
Abfuhren am 20240223
Bio 2wö
Gelber Sack
Altpapier 4wö
Restabfall

Bei der Ausgabe nach der Verkettung hätte ich einen String mit allen 4 Abfuhren erwartet. Bekomme aber nur Restabfall4wö als Ergebnis.

Das ganze wird entwickelt unter PlatformIO auf einem ESP32.

BTW: In der Arduino-IDE läuft der Code korrekt.

Nicht posten Snippets (Snippets R Us!)

Was ist der Typ für trash[i]?

Zu Anfang im Script definiert als:
String trash [anzTrash]; // Array nur für Abfuhrarten

Meinst Du mit dieser Taktik des Hinwerfens von Bröckchen an mögliche Helfer wirst Du viel Hilfe bekommen?

Gruß Tommy

verändern

  for (int i = 0; i < anzEvents; i++) {
    if (trashData[i].eventStart == eventDate){
      Serial.println(trash[i]); // nur zum Testen
      result += trash[i];
    }
  }

  for (int i = 0; i < anzEvents; i++) {
    if (trashData[i].eventStart == eventDate){
      Serial.println(trash[i]); // nur zum Testen
      result += trash[i];
    }
  }
  Serial.print("Result : "); Serial.println(result);

Mir ist bekannt, dass du gerne den gesamten Quelltext haben möchtest. Ich bin mir aber sicher, dass das hier nicht zum Ziel führt. Es geht ja nur darum zu erklären, warum die Stringverkettung in PlatformIO nicht funktioniert, in der Arduino-IDE aber sehr wohl.

Ich habe die Zeile hinzugepackt. Jetzt bekomme ich folgendes über die Konsole angezeigt:

Events ab 20240218
Abfuhren am 20240223
Bio 2wö
Gelber Sack
Altpapier 4wö
Restabfall
Restabfall4wö2wö

Bedeutet: Der Test "Result : " wird nicht ausgegeben, dafür wird noch ein 2wö hinten angehangen.

Sie könnten einen kleinen Minimalcode schreiben, der das Problem verdeutlicht.

So passiert das nie?

➜ Speicherproblem?

Deswegen bin ich ja so ratlos. Irgendetwas ist da verbogen. Ich weiß nur nicht, was ich noch wo einstellen könnte. Klar: eine Lösung wäre "Machs doch in der Arduino-IDE". Aber das wäre wie Flinte ins Korn werfen.

verändern

  Serial.print("anzEvents : "); Serial.println(anzEvents);Serial.flush(); 
  for (int i = 0; i < anzEvents; i++) {
    if (trashData[i].eventStart == eventDate) {
      Serial.print(i); Serial.write('\t'); Serial.println(trash[i]); Serial.flush(); // nur zum Testen
      result += trash[i];
    }
  }
  Serial.print("Result : "); Serial.println(result);Serial.flush(); 

Die erste Zeile wird genau so ausgegeben:

Events ab 20240218
Abfuhren am 20240223
anzEvents : 117
Bio 2wö
Gelber Sack
Altpapier 4wö
Restabfall
Restabfall4wö2wö

Die Verkettung schlägt fehl.

ich bin es leid, nur teilweise Informationen zu erhalten.

Haben Sie Folgendes verwendet?

Serial.print("anzEvents : "); Serial.println(anzEvents);Serial.flush(); 
  for (int i = 0; i < anzEvents; i++) {
    if (trashData[i].eventStart == eventDate) {
      Serial.print(i); Serial.write('\t'); Serial.println(trash[i]); Serial.flush(); // nur zum Testen
      result += trash[I];
    }
  }
  Serial.print("Result : "); Serial.println(result);Serial.flush();

und zeigen Sie genau, was der Serienmonitor gedruckt hat.

Sie sollten einen minimalen Code schreiben, der das Problem demonstriert. Es ist wahrscheinlich irgendwo anders in Ihrem Code.

mach rund um deine Funktion einen vollständigen Sketch den wir in die IDE kopieren können und ausprobieren können, dann bekommst du vermutlich auch zeitnah Hilfe.

Dann stelle ich mal den ganzen Code zur Verfügung:

#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <SPIFFS.h>

#define WIFI_SSID "your_SSID"             // Please change
#define WIFI_PASS "your_Password"

const char* sourceURL = "https://abfallkalender.regioit.de/kalender-aachen/downloadfile.jsp?format=ics&jahr=2024&ort=Aachen&strasse=10725577&hnr=10725580&zeit=-%3A00%3A00&fraktion=0&fraktion=1&fraktion=4&fraktion=7";

class TRASH {
public:
  String eventStart;
  String eventArt;
  String eventLocation;
  String eventDummy;    // nur zum Test!
  
  TRASH() {
    // Konstruktor, um Standardwerte zu setzen
    eventStart = "";
    eventArt = "";
    eventLocation = "";
    eventDummy = "";
  }
};

String iCalFile = "abfall.txt";
const int anzTrash = 150;     // Anzahl der Datenobjekte im Array
TRASH trashData [anzTrash];   // Array von TRASH-Objekten
String trash [anzTrash];      // Array nur für Abfuhrarten (Testweise)
//
int anzEvents;                // Anzahl der gelesenen Events
String today;
String eventDate;
String location;


//  ######

void wifiStart(){
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.println("Connecting Wifi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.print("Wifi RSSI=");
  Serial.println(WiFi.RSSI());
}

void setTimezone(String timezone){
  Serial.printf("  Setting Timezone to %s\n",timezone.c_str());
  setenv("TZ",timezone.c_str(),1);  //  Now adjust the TZ.  Clock settings are adjusted to show the new local time
  tzset();
}

void initTime(String timezone){
  struct tm timeinfo;

  Serial.println("Setting up time");
  configTime(0, 0, "pool.ntp.org");    // First connect to NTP server, with 0 TZ offset
  if(!getLocalTime(&timeinfo)){
    Serial.println("  Failed to obtain time");
    return;
  }
  Serial.println("  Got the time from NTP");
  // Now we can set the real timezone
  setTimezone(timezone);
}

String getStartDate(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return "Time Error";
  }

  char output[80];
  strftime(output, 80, "%Y%m%d", &timeinfo);
  time_str = String(output);
  return String(output);
}

//  ######

void removeBackslash(String& str) {
    int index = str.indexOf("\\"); // Suche nach dem Backslash in der Zeichenkette
    while (index != -1) {
        str.remove(index, 1); // Entferne den Backslash aus der Zeichenkette
        index = str.indexOf("\\", index); // Suche nach dem nächsten Backslash ab dem vorherigen Index
    }
}

void listAllSpiffsFiles(){
  File root = SPIFFS.open("/");
  File file = root.openNextFile();
  while(file){
    Serial.print("FILE: ");
    Serial.print(file.name());
    String fileName = file.name();
    File readFile = SPIFFS.open(("/" + fileName), "r");
    if (!readFile) {
      Serial.println("Fehler beim Öffnen der Datei zum Lesen");
    } else {
      Serial.print("\tDateigröße : ");
      Serial.println (readFile.available());
    }
    file = root.openNextFile();
  }
}

void downloadFile(String url, String spiffsFile) {
  HTTPClient http;
  
  // HTTP-GET-Anfrage senden
  Serial.print("HTTP GET an: ");
  Serial.println(url);
  http.begin(url);

  // HTTP-GET-Anfrage ausführen und Antwort erhalten
  int httpCode = http.GET();
  if (httpCode > 0) {
    // Wenn die Anfrage erfolgreich war, Dateiinhalt speichern
    String payload = http.getString();
    Serial.println("HTTP GET erfolgreich. Speichern der Datei auf dem ESP32...");
    removeBackslash(payload);
    //Serial.println(payload);

    // Datei auf dem ESP32 speichern
    String fn = spiffsFile;
    if (!fn.startsWith("/")) fn = "/" + spiffsFile;
    File file = SPIFFS.open(fn, "w");
    if (!file) {
      Serial.println("Fehler beim Öffnen der Datei zum Schreiben");
      return;
    }
    file.print(payload);
    file.close(); 
    } else {
      Serial.print("Fehler beim Herunterladen der Datei. HTTP-Code: ");
      Serial.println(httpCode);
  }
  http.end(); // Schließen der Verbindung
}

int readFileSelected(String spiffsFile){
  // Dateiinhalt auslesen
  String fn = spiffsFile;
  if (!fn.startsWith("/")) fn = "/" + spiffsFile;
  File readFile = SPIFFS.open(fn, "r");
  if (!readFile) {
    Serial.println("Fehler beim Öffnen der Datei zum Lesen");
    return -1;
  }

  bool found = false;
  int i = 0;

  while (readFile.available()) {
    String line = readFile.readStringUntil('\n');
    if (line.startsWith("BEGIN:VEVENT")) {
      found = true;
    }     
    //  
    if (found){
      if (line.startsWith("DTSTART:")) {
        trashData[i].eventStart = line.substring(8, 16);
      }
      if (line.startsWith("DESCRIPTION:")) {
        String value = line.substring(12);
        //trashData[i].eventArt = value + "|";
        trash[i]= value;
      }
      if (line.startsWith("LOCATION:")) {
        trashData[i].eventLocation = line.substring(9);
      }  
      if (line.startsWith("END:VEVENT")) {
        trashData[i].eventDummy = "Durchlauf#" + String(i) + "X";
        i++; 
        found = false;
      }
    }
  }
  readFile.close();
  return i; // Anzahl gelesener Events
}

String showEventsSelected(String heute){
  String result;
  result.reserve(200); // Reservieren Sie genügend Speicherplatz für das Ergebnis

  Serial.print("Events ab ");
  Serial.println(heute);
  for (int i = 0; i < anzEvents; i++) {
    if (trashData[i].eventStart > heute){
      Serial.print("Abfuhren am ");
      eventDate = trashData[i].eventStart;
      location = trashData[i].eventLocation;
      Serial.println(eventDate);
      break;
    }
  }
/*
  for (int i = 0; i < anzEvents; i++) {
    if (trashData[i].eventStart == eventDate){
      Serial.print(i);
      Serial.print("\t");
      String trashBox = trashData[i].eventArt;
      Serial.println(trashBox);
      result += trashBox;
    }
  }
*/
  Serial.print("anzEvents : "); Serial.println(anzEvents);Serial.flush();
  for (int i = 0; i < anzEvents; i++) {
    if (trashData[i].eventStart == eventDate){
      Serial.print(i); Serial.write('\t'); Serial.println(trash[i]); Serial.flush(); // nur zum Testen
      result += trash[i];
    }
  }
  Serial.print("Result : "); Serial.println(result);Serial.flush();
  return result;

}


void setup() {
  Serial.begin(115200);
  Serial.println();

  // Verbindung zum Wi-Fi-Netzwerk herstellen
  wifiStart();
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Verbindung zum Wi-Fi-Netzwerk herstellen...");
  }
  Serial.println("Verbunden mit dem Wi-Fi-Netzwerk");

  // Starten des Dateisystems
  if (!SPIFFS.begin(true)) {
    Serial.println("Fehler beim Starten des Dateisystems");
    return;
  }
  
  // Init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, NTP_SERVER);
  today = getStartDate();
  
  //downloadFile(URL, iCalFile);
  listAllSpiffsFiles();
  //
  Serial.println("=0==============");
  anzEvents = readFileSelected(iCalFile);
  Serial.print (anzEvents);
  Serial.println(" Events eingelesen");
  Serial.println("=0==============");
  //
  String _Abfuhren = showEventsSelected("20240218");
  //
  Serial.println("=1==============");
  Serial.println(_Abfuhren);
  Serial.println("=2==============");
  Serial.println(location);
  Serial.println("=3==============");
  //
}

void loop(){
  yield();
}

Bitte beachten: In der Arduino-IDE funktioniert der Code. Ich will aber mit VSC-PlatformIO entwickeln !!

Wenn Sie anzTrash viel kleiner machen, etwa 15 oder 20, sehen Sie dasselbe Problem?

Wenn ich die iCal-Datei frisch importiere (am Jahresanfang) hat die 117 Einträge. Bis dahin könnte ich ja runter gehen. Aber nächstes Jahr können es dann wieder 122 sein.

Du könntest es wenigstens jetzt mal machen, um Speicher frei zu bekommen.

Ich hab die größe mal auf 15 reduziert:

Events ab 20240218
Abfuhren am Bio 2wö
anzEvents : 15
Bio 2wö
Result : Bio 2wö

Sie testen nicht das Überlaufverhalten des trashData Arrays.