ESP - UDP (ESPAsyncUDP) - Paket zerlegen

Hallo zusammen,

ich bin am verzweifeln. Ich versuche nun seit 2 Tage eine UDP Kommunikation zwischen Python und einem ESP8266 hinzubekommen.

Ziel ist es, einen RGB Controller zu haben, den man mit UDP Paketen steuern kann.

Das Python Skript sendet dazu die RGB Daten (0-255) als ein Paket an den ESP:

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
packer = struct.Struct('I I I')
packed_data = packer.pack(*color)
sock.sendto(packed_data, (address["ip"], 2200))

So weit so gut, schein schonmal zu funktionieren. Das mit dem Struct wurde mal irgendwo für die Übertragung per UDP empfohlen.

Jetzt die Seite ESP:

Was ich bisher erreicht habe: Datenmüll, Nichts, ESP stürzt ab

void light(AsyncUDPPacket &packet) {

    RGB *rgbIn;

    ESP_LOGD("rgbudp", "Light packet arrived");
    uint8_t *packetBuffer = packet.data();
    uint32_t packetSize = packet.length();
    rgbIn = (RGB*)packet.data();
    auto call = color_led->turn_on(); 
    ESP_LOGD("rgbudp", "Red: %d", (rgbIn->r));

    if (((packet.data()[1])+(packet.data()[2])+(packet.data()[3])) == 0) {
          ESP_LOGD("rgbudp", "No Values for RGB or Null");

    } else {
      ESP_LOGD("rgbudp", "red: %d green: %d blue: %d", packetBuffer[0], packetBuffer[1] ,packetBuffer[2]);
    }
  }

  typedef struct {

    int r;
    int g;
    int b;

  }RGB;
[/color]

Ihr seht hier meine kläglichen Versuche, das Paket entsprechend zu verarbeiten und zu zerlegen. Allerding ohne Erfolg.
Wie es mir scheint ist besonders die Verarbeitung von mehreren Werten innerhalb eines UDP Pakets ein gut gehütetes Geheimnis. An Beispielen finde ich leider nur welche, in denen ein einziger Wert oder ein String übertragen und per Serial.Print aufgegeben wird.
Leider bin ich durch starke Medikament in der Aufnahmefähigkeit sehr eingeschränkt und kann mir aus den Beispielen leider nichts backen.
Ich hoffe, dass mir hier jemand vielleicht eine Lösung geben kann?

Evtl. ist die Bytefolge auf dem PC anders. Lass Dir doch erst mal alle Bytes auf der Empfangsseite in HEX anzeigen, damit Du siehst, was ankommt.

Gruß Tommy

Hi Tommy,

danke für den Tip. Das hatte ich auch schon vor, aber da hänge ich genau so.
Bei meinem Konstrukt handelt es sich um einen Raspberry und der ESP wird über ESPHOME programmiert. Da kann ich mir nur was mit der Funktion ESP_LOGD ausgeben. Dazu kommt noch die Funktion ESPAsyncUDP.

Soweit ich schon rausbekommen habe und keinem schweren Irrtum unterliegen handelt es sich bei dem Paket um uint8*. An die Daten kommt man angeblich mit packet.data(). Aber wie wo was genau da nun drinsteht und wie ich mir den Inhalt eben dieses Pakets per ESP_LOG ausgeben kann ist mir genau so ein Rätsel.

Egal wie ich dieses packet.data() anfasse, ob direkt mit z.B. r = packet.data() oder r = packet.data()[0], entweder gibt es gar keine Daten oder der ESP schmiert ab.

Ich hänge da völlig in der Luft.

Vermutlich (habe nur kurz in einen Header geschaut) liefert packet.data() den Zeiger auf die Daten. Das ist äquivalent zu einem C-Array von bytes.

uint8_t* r;
r = packet.data();
das_byte_18_ist = r[17];

Im Normalfall (Arduino-IDE) gibt man das Array einfach über Serial aus. ESPHOME kenne ich nicht, damit musst Du selbst klar kommen.

Gruß Tommy

wno158:
Vermutlich (habe nur kurz in einen Header geschaut) liefert packet.data() den Zeiger auf die Daten. Das ist äquivalent zu einem C-Array von bytes.

uint8_t* r;

r = packet.data();
das_byte_18_ist = r[17];

wno158:
Vermutlich (habe nur kurz in einen Header geschaut) liefert packet.data() den Zeiger auf die Daten. Das ist äquivalent zu einem C-Array von bytes.

uint8_t* r;

r = packet.data();
das_byte_18_ist = r[17];

Ja, irgendwie scheint das genau so zu sein. Jetzt habe ich aber das Problem, dass in packet.data() nicht nur das r drinsteckt sondern auch g und b.

Das r von wno158 ist nicht Dein r. Nenne es besser inhalt.

Gruß Tommy

Ach so - Entschuldigt bitte, das mit der RGB-Struktur habe ich übersehen.

Kommen die drei Farbwerte im Paket als ASCII-Zeichen oder binär an?
Davon hängt es ab, wie Du den Array "Inhalt" dann auswerten musst, um die Farben zu extrahieren.

Gib doch mal das ganze Paket in einer Schleife zeichenweise mit Serial.println(inhalt[i], HEX) aus - dann sollte das fast selbsterklärend sein.

Um Gottes Willen. Da gibt es nichts wofür du dich entschuldigen musst. Ich bin ja froh, dass ihr mir hier helfen wollt.

Ich sende die Pakete binär. Als bytearray habe ich es schon versucht oder als Struct.

Binär - okay.
Deine Farben sind int (zwei Byte).
Bekommst du auch zwei Byte pro Farbe und die dann auch noch in der richtigen Reihenfolge?

Najaaaa, jetzt wird es ganz wild.
Ich bin jetzt mal umgeschwenkt und habe mir einen ESP mit Arduino verhaftet um mit dem Serial Print was zu machen.

Reihenfolge scheint zu stimmen. Ich habe gerade eben erst nach der Endianness geschaut. Beide sind little.

Jetzt kommt aber folgendes:

sock.sendto("Test".encode(), ("192.168.10.60", 2200))
ergibt:
UDP Packet Type: Unicast, From: 192.168.10.253:47241, To: 192.168.10.60:2200, Length: 4, Data: Test
Hier habe ich eine Länge und einen Inhalt

sock.sendto(bytes(color[0]), ("192.168.10.60", 2200))
ergibt:
UDP Packet Type: Unicast, From: 192.168.10.253:49131, To: 192.168.10.60:2200, Length: 110, Data:
Hier habe ich eine Länge, aber keinen Inhalt bzw. er kann mit dem Inhalt nix anfangen?

Jetzt wär es ja fast das einfachste, alles was int ist vorher in String umzuwandeln, aber das wäre ja bescheu... bescheiden oder?

Ich nehme das mit dem binär jetzt mal zurück. Sicher bin ich mir dabei nämlich nicht so ganz.

Ich hab dem Sender jetzt das Senden so "beigebracht":

sock.sendto(encode_int_array([color[0], color[1], color[2]]), ("192.168.10.60", 2200))

def encode_int_array(int_list):
    buf = struct.pack("!i" + "i" * len(int_list), len(int_list), *int_list)
    return buf

Das führt zu folgendem Ergebnis:

UDP Packet Type: Unicast, From: 192.168.10.253:50875, To: 192.168.10.60:2200, Length: 16, Data: komische Zeichen

Sende ich nur eine Farbe, ist die Länge 8.

Ich habe das Gefühl, ich stehe kurz davor bin aber trotzdem noch meilenweit entfernt.

Auf der Python/Pi-Seite kann ich leider nicht helfen.

Data: komische Zeichen

Nochmal zurück zu #1 von Tommy und meinem #7 letzter Satz:
Zeig uns die Bytes, die ankommen und sag noch, was Du eigentlich (vermutlich) reingesteckt hast.

Dann wird sich der Knoten schon durchschlagen lassen.

Eine Umwandlung in Text wäre nicht ganz so bescheuert wie Du denkst. Wenn ich so sehe, was meine Kollegen in der Firma alles an JSON von kleinen Geräten aus an die großen Server schicken lassen - als Bitpfriemler wird mir da schlecht. Bandbreite scheint aber heutzutage nicht mehr das Problem zu sein.

andiaa:
UDP Packet Type: Unicast, From: 192.168.10.253:49131, To: 192.168.10.60:2200, Length: 110, Data:
Hier habe ich eine Länge, aber keinen Inhalt bzw. er kann mit dem Inhalt nix anfangen?

Doch, Du hast Inhalt, der ist nur nicht druckbar.
Was meinst Du, warum Dir empfohlen wurde, die Bytes HEX auszugeben? Solange Du das ignorierst, wirst Du wohl weiter "heiteres Byteraten" (in Anlehnung an eine historische Sendung - welches Schweinderl hättens gern?) machen müssen.

Gruß Tommy

Du kannst testweise die UDP Pakete broadcasten und dann am PC mit zB Packetsender in hex überprüfen. Da siehst du dann schon mal, ob auch das gesendet wird, was du denkst, das gesendet wird.

Heureka, Ich habe es hinbekommen. Ich habe alles verworfen und nochmal von vorne angefangen. Und siehe da. Es funktioniert mit dem Struct, welches ich auch gleich mal ein wenig aufgeblasen habe:

Sender:

packer = struct.Struct('I I I I I I I')
packed_data = packer.pack(color_led, white_led, *color, brightness, transitiontime)
sock.sendto(packed_data, (address["ip"], 2200))

Empfänger:

struct color {
      int color_led;
      int white_led;
      int r;
      int g;
      int b;
      int bri;
      int transitiontime;
    }color;

    memcpy(&color, packet.data(), sizeof(color));

Damit kommen die Daten sauber an.

Drauf gekommen bin ich tatsächlich dank euers Tipps mit der Ausgabe mittels serial.print.
Irgendwo muss mir bei den ersten Versuchen mittels Struct ein blöder Fehler unterlaufen sein.
Bei diesem Versuch steckte eine böse Falle drin:

sock.sendto(encode_int_array([color[0], color[1], color[2]]), ("192.168.10.60", 2200))[color=#222222][/color]
[color=#222222][/color]
def encode_int_array(int_list):[color=#222222][/color]
  buf = struct.pack("!i" + "i" * len(int_list), len(int_list), *int_list)[color=#222222][/color]
  eturn buf

Und zwar wird bei struct.pack durch das !i mitgeteilt, dass es sich um Big Endian handelt. Raspi und ESP sind aber beide little endian. Das konnte ja dann nur in die Hose gehen.
Egal. Läuft jetzt und steht hier falls mal jemand anderes vor diesem Problem steht.

Nochmals vielen lieben Dank an euch alle für die Hilfe und eure Zeit!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.