Solaranzeige ESP32 1602 Displays

Hallo bin ganz neu in Sachen Arduino und habe auch nicht so die Programmiererfahrung.

Kann mir zwar aus Vorlagen was zusammenbasteln, aber etwas von 0 an programmieren klappt noch nicht.

Ich möchte mir eine Anzeige für meine Solaranlage basteln mit mehreren 1602 Displays.

Habe auch ein Code gefunden der mit einem Display super funktioniert, aber ich schaffe es nicht die MQTT topics auf mehrere Displays zu verteilen.

MQTT Server läuft einwandfrei nur bei der Programmierung des ESP32 hapert es. Wenn mir da jemand helfen könnte wäre das super.

Bin ich richtig informiert das ich maximal 6 Displays an einen ESP32 anschließen kann zwecks Adressierung

Das ist mein momentaner Code:


#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>  // This library is already built in to the Arduino IDE
#include <LiquidCrystal_I2C.h> //This library you can add via Include Library > Manage Library > 
LiquidCrystal_I2C lcd_pverzeugung(0x27, 16, 2);
LiquidCrystal_I2C lcd_verbrauch(0x26, 16, 2);
LiquidCrystal_I2C lcd_akkuladezustand(0x25, 16, 2);

/*0x27 means the address of this 1602 I2C LCD display,different lcd may have the different address,
                                     if the LCD do not work,please read below post about how to get the right address for your I2C LCD dispaly:
                                     http://osoyoo.com/2014/12/07/16x2-i2c-liquidcrystal-displaylcd/ */
// Update these with values suitable for your network.
const char* ssid = "Bärenhöhle";//put your own wifi ssid here
const char* password = "xxxxxx";// put your wifi password here
//const char* mqtt_server = "broker.mqttdashboard.com";// choose your mqtt server
const char* mqtt_server = "192.168.115.7";



WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
void setup_wifi() {
   delay(100);
   
  // We start by connecting to a WiFi network
    Serial.print("Connecting to ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) 
    {
      delay(500);
      Serial.print(".");
    }
  randomSeed(micros());
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) 
{
  Serial.print("Command from MQTT broker is : [");
  Serial.print(topic);
   Serial.println();
  Serial.print(" publish data is:");
  lcd_pverzeugung.clear();
  {
  for(int i=0;i<length;i++)
  {
    Serial.print((char)payload[i]);  
    lcd_pverzeugung.setCursor(0, 0);
    lcd_pverzeugung.print("PV Erzeugung"); // Start Print text to Line 1
    lcd_pverzeugung.setCursor(i, 1);
    lcd_pverzeugung.write((char)payload[i]);

    lcd_verbrauch.setCursor(0, 0);
    lcd_verbrauch.print("Verbrauch"); // Start Print text to Line 1
    lcd_verbrauch.setCursor(i, 1);
    lcd_verbrauch.write((char)payload[i]);

    lcd_akkuladezustand.setCursor(0, 0);
    lcd_akkuladezustand.print("Akku Ladung"); // Start Print text to Line 1
    lcd_akkuladezustand.setCursor(i, 1);
    lcd_akkuladezustand.write((char)payload[i]);
    
    }
  }   
    
  Serial.println();
} //end callback

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) 
  {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    //if you MQTT broker has clientID,username and password
    //please change following line to    if (client.connect(clientId,userName,passWord))
    if (client.connect(clientId.c_str()))
    {
      Serial.println("connected");
     //once connected to MQTT broker, subscribe command if any
   
      client.subscribe("pverzeugung");
     // client.subscribe("einspeisung");
     // client.subscribe("bezug");
      client.subscribe("verbrauch");
      client.subscribe("akkuladezustand");
     // client.subscribe("akkuladung");
     // client.subscribe("akkuentladung");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 6 seconds before retrying
      delay(6000);
    }
  }
} //end reconnect()

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  
  lcd_pverzeugung.init();   // initializing the LCD
  lcd_pverzeugung.backlight(); // Enable or Turn On the backlight 

  lcd_verbrauch.init();   // initializing the LCD
  lcd_verbrauch.backlight(); // Enable or Turn On the backlight 

  lcd_akkuladezustand.init();   // initializing the LCD
  lcd_akkuladezustand.backlight(); // Enable or Turn On the backlight 
  
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.setCallback(callback);
  client.loop();

}

Der PCF8574 (Datenblatt) lässt sich auf eine von 6 Adressen einstellen.
Somit lassen sich 6 8 (siehe #9) dieser Chips an einem Strang betreiben.
Das müssen nicht unbedingt Displays sein...

An was klemmt es denn? An der Adressvergabe?
In diesem Datenblatt ist beschrieben, wie die Adressvergabe funktioniert. - Hinweis: Da ist ein 8574A verbaut, mit dem 6 weitere Adressen zur Verfügung stehen. Aber das Prinzip sollte klar sein, wenn Du an Stelle mit 0x38 mit 0x27 beginnst :wink:

Ich bekomme die topics nicht auf die Displays verteilt.

Zeile 1 möchte ich immer manuell setzen und Zeile 2 soll immer den entsprechenden Wert abrufen. Ich bekomme zwar alle Werte mit MQTT abgerufen, aber ich weiß nicht wie ich diese den Displays zuweisen kann. meinte Kenntnisse sind da auch sehr beschränkt. hab den ESP erst seit ein paar Tage und davor noch nie mit sowas gearbeitet.

image

Du schreibst auf jedes Display die gleiche Variable:

also zeigt jedes Display das gleiche an.
da wirst für jedes Display irgend was anderes brauchen oder?

Kannst du die unterschiedlichen Werte bereits auf der Seriellen Schnittstelle ausgeben?

VERMUTLICH

musst du jedem Display eine fixe Antwortzeile zuweisen.

lcd_pverzeugung.write((char)payload[0);
lcd_verbrauch.write((char)payload[1]);
lcd_akkuladezustand.write((char)payload[2]);

und nicht in der For-Schleife abarbeiten sondern jedes Display nur einmal ausgeben.

ja auf der Schnittstelle kann ich alle Werte sehen die ich brauche.

Kannst du mir den Code vielleicht anpassen?

Na schick.
Kannst Du mal schreiben, was Du auf dem Seriellen Monitor an dieser Stelle:

void callback(char *topic, byte *payload, unsigned int length)
{
  Serial.print("Command from MQTT broker is : [");
  Serial.print(topic);
  Serial.println();

rausbekommst?.
Dann kannn man darauf abgleichen.

na dann.

  • mach nur die Serielle Ausgabe in der For - Schleife,
  • aber die Ausgaben auf die LCDs machst außerhalb der Schleife mit den geänderten Zeilen.

Programmieren musst schon selber, ist ja DEIN Programm.

Das scheint mir momentan der Renner :sunglasses:

Anstelle 16x2 gibt es auch 20x4, da paßt mehr Info drauf. Nur so als Hinweis wegen der nächsten Frage.

Ich kenne Dein Display mit I²C-Portexpander nicht. Meins hat drei Adresslötbrücken, was 2³ = 8 Adressen ergibt:

Die 6 Adressen erschließen sich mir nicht, ich zähle acht. Oder?

Schön für Dich, aber ich leider nicht.

Vermutlich willst Du je nach Inhalt von topic den Inhalt auf die Displays verteilen.

AZ bei Amazon
AZ bei sich auf der Homepage
In ihrem PDF sprechen sie aber auch von 8...

Habe ich auch gelesen, aber etwas später lese ich dann:

grafik

Da möchte ich dann doch lieber dem Datenblatt mit acht trauen.

kann ich dir heute abend schreiben. Bin gerade auf arbeit

... spätestens seit #3 soll aber klar sein, dass die Adressierung nicht das Problem ist.

Aber wenn ihr ihn weiterhin verwirren wollt:
PCF8574P, PCF8574T, PCF8574TS unterstützen die (Arduino like) Adressen 0x20 - 0x27.
Die ICs PCF8574AP, PCF8574AT und 8574A - also jene mit A in der Gehäusebezeichnung - verwenden die Adressen 0x38 - 0x3F

Da ich den T gerade drauf habe...
Der antwortet auf 0x27.
https://www.mouser.de/datasheet/2/302/PCF8574_PCF8574A-1127673.pdf
Jetzt ist die Verwirrung komplett.
Es kommt nämlich auch noch darauf an, wer die produziert.
Siehe oben

Ja, mach das.
Dann geht das recht zügig :wink:

Danke, in meinem LCD-Testprogramm steht "wenn nicht 0x27 dann wähle 0x3F", da muß in meiner Bastelkiste wohl so einer rumfliegen.

Aber 0x30 - 0x3F sind 16 Adressen, richtig wäre also 0x38 - 0x3F. Oder?

Richtig, ein Blick in ein altes Datenblatt (1997) von Phillips hat mich gerade irritiert, da werden die Buchstaben wohl anders verwendet:

@pfreak2000: In der Arduino-Umgebung werden die Adressen des Datenblattes durch zwei geteilt verwendet, weil das R/W-Bit weggelassen wird. Wenn im Datenblatt 0x4E steht, wird in der IDE meist 0x27 verwendet.

Beim selben Portexpandertyp kannst Du acht LCDs adressieren, bei zwei unterschiedlichen auch sechzehn. Allerdings könntest Du auch einen anderen Displaytyp in Erwägung ziehen, wenn Du mehr anzeigen möchtest :slightly_smiling_face:

Die Beleuchtung der LCDs benötigt recht viel Strom, bei mehreren solltest Du eine externe Stromversorgung verwenden.

Die 3 LCD verwende ich nur zum basteln. später verwende ich OLEDs

Ich habe kein MQTT, aber wenn ich Dich richtig verstehe, hängt es bei der Aufteilung nacheinender eintreffender Nachrichten auf mehrere Displays. Das simuliere ich mal in loop und die Aufteilung erfolgt in der Funktion callback. Getestet mit ESP32:

#include <Wire.h>  // This library is already built in to the Arduino IDE
#include <LiquidCrystal_I2C.h> //This library you can add via Include Library > Manage Library > 
LiquidCrystal_I2C lcd_pverzeugung(0x27, 16, 2);
LiquidCrystal_I2C lcd_verbrauch(0x26, 16, 2);
LiquidCrystal_I2C lcd_akkuladezustand(0x25, 16, 2);

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println("\nStart");

  lcd_pverzeugung.init();   // initializing the LCD
  lcd_pverzeugung.backlight(); // Enable or Turn On the backlight

  lcd_verbrauch.init();   // initializing the LCD
  lcd_verbrauch.backlight(); // Enable or Turn On the backlight

  lcd_akkuladezustand.init();   // initializing the LCD
  lcd_akkuladezustand.backlight(); // Enable or Turn On the backlight
}

void loop() {
  char t1[] = "Aaa";
  byte p1[] = {7, 7, 3};
  unsigned int l = sizeof(p1);
  callback( t1, p1, l );

  char t2[] = "Bbb";
  byte p2[] = {4, 7, 1, 1};
  l = sizeof(p2);
  callback( t2, p2, l );

  char t3[] = "Ccc";
  byte p3[] = {4, 2};
  l = sizeof(p3);
  callback( t3, p3, l );

  delay(10000);
}

void callback(char* topic, byte* payload, unsigned int length)
{
  Serial.print("Command from MQTT broker is : ");
  Serial.print(topic);
  Serial.println();
  Serial.print(" publish data is:");

  if ( !strncmp (topic, "Aaa", sizeof(topic)) )  // http://www.cplusplus.com/reference/cstring/strncmp/
  {
    lcd_pverzeugung.clear();
    lcd_pverzeugung.setCursor(0, 0);
    lcd_pverzeugung.print("PV Erzeugung");
    lcd_pverzeugung.setCursor(0, 1);
    for (byte i = 0; i < length; i++)
    {
      Serial.print(payload[i]);
      lcd_pverzeugung.print(payload[i]);
    }
  }
  if ( !strncmp (topic, "Bbb", sizeof(topic)) )
  {
    lcd_verbrauch.clear();
    lcd_verbrauch.setCursor(0, 0);
    lcd_verbrauch.print("Verbrauch");
    lcd_verbrauch.setCursor(0, 1);
    for (byte i = 0; i < length; i++)
    {
      Serial.print(payload[i]);
      lcd_verbrauch.print(payload[i]);
    }
  }
  if ( !strncmp (topic, "Ccc", sizeof(topic)) )
  {
    lcd_akkuladezustand.clear();
    lcd_akkuladezustand.setCursor(0, 0);
    lcd_akkuladezustand.print("Akku Ladung");
    lcd_akkuladezustand.setCursor(0, 1);
    for (byte i = 0; i < length; i++)
    {
      Serial.print(payload[i]);
      lcd_akkuladezustand.print(payload[i]);
    }
  }
  Serial.println();
} //end callback

Dann brauchen wir uns bei den LCDs ja nicht mit Feinheiten aufzuhalten :slightly_smiling_face:

danke, genau richtig.
werde das nacher testen.

Muss ich das Aaa usw. noch mit den topic namen anpassen?

Die werden auch heute noch genauso verwendet.
P - Dip 16, T - SO16, TS - SSOP20 -> die fangen alle mit 0x20 an und enden auf 0x27
grafik

Das A ist der nächste Chip, der fängt bei 0x38 an
grafik

Tabellen aus dem NXP-Dabla
Darum habe ich die Zuordnung von @noiasca als Verwirrung angesehen, weil das genau anders rum ist.

Bei TI bekommen die auch je nach Bauform einen anderen Kennbuchstaben.
Das DIP16 ist dann DW oder N, Ein DIP 20 heisst DGV oder PW und SSOP 20 heisst da RGY.

Ich habe ein altes Datenblatt:
grafik
Ich habe das Alter nur nicht gleich bemerkt, mich gibt es ja auch schon etwas länger :crazy_face:

Ja, das sind nur Platzhalter, die Du durch "Verbrauch" oder sowas ersetzen kannst. Ich habe leider keinen blassen Schimmer, was Deine Datenbank liefert.