Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
AZ-Delivery
Published

Newsreader on matrix display

In this project, the time, date and the latest headlines are to be displayed as a ticker on an LED matrix, using timeserver and RSS Feed

BeginnerFull instructions provided1.5 hours819
Newsreader on matrix display

Things used in this project

Hardware components

D1 mini ESP32
×1
LED Matrix 8x32
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Wiring

Code

News Reader

Arduino
#include <LG_Matrix_Print.h> //Bibliothek für die Matrixanzeige
#include <HTTPClient.h>
//Web Client für den Empfang des RSS-Feeds
#include <SPIFFS.h> //Filesystem zum Speichern der Konfiguration
#include <WebServer.h> //Webserver für die Konfiguration
#include <ESPmDNS.h> //Multicast DNS für Namensauflösung
#include <WebConfig.h>
//Bibliothek zur Konfiguration über eine Webseite
#include <TinyXML.h> //XML-Interpreter zum Lesen des RSS-Feed

#define LEDMATRIX_CS_PIN 16 //CS Pin der LED Matrix

// Anzahl der 8x8 LED Segmente
#define LEDMATRIX_SEGMENTS 4

// Timeout zum Lesen des RSS-Feed in Sekunden
#define READ_TIMEOUT 10

//Prameter für das Konfigurations-Formular
String params = "["
  "{"
  "'name':'ssid',"
  "'label':'Name des WLAN',""'type':"+String(INPUTTEXT)+","
  "'default':''"
  "},"
  "{"
  "'name':'pwd',"
  "'label':'WLAN Passwort',"
  "'type':"+String(INPUTPASSWORD)+","
  "'default':''"
  "},"
  "{"
  "'name':'rssUrl',"
  "'label':'RSS Feed URL',"
  "'type':"+String(INPUTTEXT)+","
  "'default':''"
  "},"
  "{"
  "'name':'ntp',"
  "'label':'NTP Server',"
  "'type':"+String(INPUTTEXT)+","
  "'default':'de.pool.ntp.org'"
  "},"
  "{"
  "'name':'maxNews',"
  "'label':'Schlagzeilen',"
  "'type':"+String(INPUTNUMBER)+","
  "'min':1,'max':10,"
  "'default':'1'"
  "},"
  "{"
  "'name':'intens',"
  "'label':'Helligkeit',"
  "'type':"+String(INPUTNUMBER)+","
  "'min':1,'max':15,"
  "'default':'1'"
  "},"
  "{"
  "'name':'disptime',"
  "'label':'Anzeigedauer (s)',"
  "'type':"+String(INPUTNUMBER)+","
  "'min':1,'max':30,"
  "'default':'5'"
  "}"
  "]";

//Web Server Instanz
WebServer server;
//Web Konfigurations Instanz
WebConfig conf;
//LED Matrix Instanz
LG_Matrix_Print lmd(LEDMATRIX_SEGMENTS, LEDMATRIX_CS_PIN);
//XML Interpreter Instanz
TinyXML xml;

//Globale Variablen
uint32_t last = 0; //Zeit der letzten Aktion in ms
uint8_t buffer[2000]; //Buffer für XML-Interpreter
String news[10]; //Speicher für Nachrichten (Max. 10)
uint8_t newsCnt = 0; //Anzahl der aktuellen Nachrichten im Speicher
uint8_t curNews = 0; //Index der gerade angezeigten Nachricht
uint8_t dispMode = 0; //Art der Anzeige 0=Zeit, 1=Datum, 2=News;

//Diese Funktion wird vom XML-Interpreter aufgerufen,
//wenn ein XML-Tag gelesen wurde
//tagName enthält den vollständigen XML-Pfad des Tags,
//data den Inhalt des Tags
void XML_callback(uint8_t statusflags, char* tagName, uint16_t tagNameLen, char* data, uint16_t dataLen) {
  if (statusflags & STATUS_TAG_TEXT) {
    //Serial.println(tagName);
    //wenn wir einen Titel-Tag finden,
    //und die maximale Anzahl der Meldungen noch
    //nicht erreicht ist, wird die Meldung gespeichert
    //und der Zähler erhöht
    if (strcasecmp(tagName,"/rss/channel/item/title")==0) {
      data[dataLen] = '\0';
      if (newsCnt < conf.getInt("maxNews")) {
      //Die maximale Anzahl der Nachrichten wird
      //aus der Konfiguration gelesen
        news[newsCnt] = data;
        newsCnt++;
      }
    }
  }
}

//WLAN Verbindung initialisieren
boolean initWiFi() {
  boolean connected = false;
  WiFi.mode(WIFI_STA);
  Serial.print("Verbindung zu ");
  Serial.print(conf.values[0]);
  Serial.println(" herstellen");
  if (conf.values[0] != "") {
    //wenn eine SSID bekannt ist,
    //wird versucht eine Verbindung herzustellen
    WiFi.begin(conf.values[0].c_str(),conf.values[1].c_str());
    uint8_t cnt = 0;
    while ((WiFi.status() != WL_CONNECTED) && (cnt<20)){
      delay(500);
      Serial.print(".");
      cnt++;
    }

Serial.println();
    if (WiFi.status() == WL_CONNECTED) {
      Serial.print("IP-Adresse = ");
      Serial.println(WiFi.localIP());
      connected = true;
    }
  }

//konnte keine Verbindung hergestellt werden,
  //wird ein Accesspoint gestartet
  //der Accesspoint hat kein Passwort. Über die IP-Adresse 
  //192.168.4.1 kann die Konfiguration durchgeführt werden
  if (!connected) {
    WiFi.mode(WIFI_AP);
    WiFi.softAP(conf.getApName(),"",1);
  }
  return connected;
}

//Diese Funktion wird aufgerufen,
//wenn der Webserver eine Anfrage erhält
void handleRoot() {
//Die Anfrage wird an die Konfigurationsinstanz weitergegeben
  conf.handleFormRequest(&server);
}

//Neue Nachrichten vom RSS-Feed lesen
void getNews() {
  String error = "";
  if(WiFi.status()== WL_CONNECTED){
    //HTTP Client
    HTTPClient http;
    Serial.print("[HTTP] begin...\n");
    //url aus der Konfiguration
    http.begin(conf.getValue("rssUrl"));

Serial.print("[HTTP] GET...\n");
    // Anfrage abschicken
    int httpCode = http.GET();

// httpCode ist im Fall eines Fehlers negativ
    if(httpCode > 0) {
      // HTTP Antwort vom Server erhalten
      Serial.printf("[HTTP] GET... code: %d\n", httpCode);
      if(httpCode == HTTP_CODE_OK) {
        String payload = http.getString();
        xml.reset();
        for (uint16_t i=0; i<payload.length(); i++) xml.processChar(payload[i]);
      }
      else{
        error = "Server antwortet mit "+String(httpCode);
      }
    } else {
        error = "Server antwortet mit "+http.errorToString(httpCode);
    }

http.end();
    if (newsCnt > 0) {
      //Falls Nachrichten empfangen wurden,
      //wird die erste Nachricht angezeigt
      curNews = 0;
      lmd.ticker(news[0],100);
    }
  } else {
      initWiFi();
      error = "Keine Internetverbindung!";
  }
  if (error != "") {
    news[0] = error;
    newsCnt = 1;
    curNews = 0;
    lmd.ticker(news[0],100);
  }
}

//Die aktuelle Uhrzeit wird angezeigt wenn start wahr ist
void showTime(boolean start){
  if (start) {
    Serial.println("Time Start");
    last = millis();
    char sttime[10];
    struct tm timeinfo;
    dispMode=0;
    if(getLocalTime(&timeinfo)){
      strftime(sttime, sizeof(sttime), "%H:%M ", &timeinfo);
      lmd.printText(0,String(sttime));
      lmd.display();
    } else {
    //liefert die RTC keine Werte so wird ??:?? angezeigt
      lmd.printText(0,"??:?? ");
      lmd.display();
    }

} else {
    //Wenn das Ende der Anzeigedauer erreicht wurde,
    //wird auf Datum umgeschaltet
    if ((millis()-last) > (conf.getInt("disptime")*1000)) {
      showDate(true);
    }
  }
}

//Das aktuelle Datum wird angezeigt wenn start wahr ist
void showDate(boolean start) {
  if (start) {
    Serial.println("Date Start");
    last = millis();
    char sttime[10];
    struct tm timeinfo;
    dispMode = 1;
    if(getLocalTime(&timeinfo)){
      strftime(sttime, sizeof(sttime), "%d.%b ", &timeinfo);
      lmd.printText(0,String(sttime));
      lmd.display();
    } else {
      //liefert die RTC keine Werte so wird ??.??? angezeigt
      lmd.printText(0,"??.???");
      lmd.display();
    }
  } else {
    //Wenn das Ende der Anzeigedauer erreicht wurde,
    //wird auf News umgeschaltet
    if ((millis()-last) > (conf.getInt("disptime")*1000)) {
      showNews(true);
    }
  }
}

//Eine Nachricht wird angezeigt wenn start wahr ist
//werden Nachrichten vom Server geholt und
//die erste Nachricht angezeigt sonst die nächste
void showNews(boolean start) {
  if (start) {
    Serial.println("News Start");
    if (curNews == 0) {
      getNews();
    } else {
      lmd.ticker(news[curNews],100);
    }
    dispMode = 2;
  } else {
  //der Ticker wird aktualisiert. Wenn das Ende der Nachricht erreicht
  //wurde wird auf die nächste Nachricht weitergeschaltet.
  //Die Anzeige wird auf Zeitanzeige umgeschaltet
    if (!lmd.updateTicker()) {
      curNews++;
      if (curNews >= newsCnt) curNews = 0;
      showTime(true);
    }
  }
}

//Wird einmal beim Start des Programms ausgeführt
void setup() {
  //Filesystem initialisieren und
  //falls noch nicht geschehen, formatieren
  SPIFFS.begin(true);
  //Serielle Schnittstelle starten
  Serial.begin(115200);
  //XML-Interpreter initialisieren
  xml.init((uint8_t *)buffer, sizeof(buffer), &XML_callback);
  //Formular zur Webkonfiguration vorbereiten
  conf.setDescription(params);
  //Konfiguration falls vorhanden aus dem Filesystem lesen
  conf.readConfig();
  // Anzeige initialisieren
  lmd.setEnabled(true);
  lmd.setIntensity(conf.getInt("intens")); // 0 = low, 10 = high
  lmd.clear();
  lmd.display();
  //WLAN Verbindung herstellen
  initWiFi();
  //Multicast DNS starten
  char dns[30];
  sprintf(dns,"%s.local",conf.getApName());
  if (MDNS.begin(dns)) {
    Serial.println("MDNS responder gestartet");
  }
  //Webserver starten
  server.on("/",handleRoot);
  server.begin(80);
  delay(1000);
  //Wenn eine Internetvebindung besteht, die Echtzeituhr des ESP32
  //mit Daten vom Zeitserver starten
  if (WiFi.status()== WL_CONNECTED) configTzTime("CET-1CEST,M3.5.0/03,M10.5.0/03", conf.getValue("ntp"));
  showTime(true);
}

void loop() {
  if (millis() < last) last=millis();
  //falls ein Überlauf auftrat nach etwa 50 Tagen
  //Anfragen des Webserver behandeln
  server.handleClient();
  //Anzeige aktualisieren
  switch (dispMode) {
    case 0: showTime(false); break;
    case 1: showDate(false); break;
    case 2: showNews(false); break;
  }
}

Github file

https://github.com/GerLech/WebConfig/blob/master/README.md

Credits

AZ-Delivery
27 projects • 3 followers
Projects that spark curiosity. Just DIY with us. Visit our shop with regularly new Blogs and free E-Books.
Contact

Comments

Please log in or sign up to comment.