Mehrere Variablenwerte von Client an Server schicken

Hallo
Ich habe zwei Nodemcu’s (ESP8266-1E), bei denen einer als Server im AP-Modus arbeitet und die andere ein Client ist. Den Code für Server und Client habe ich aus den Netz geladen. Ich möchte, dass der am Client angeschlossene DS18B20 die Temperatur an den Server sendet und das ein Taster der auch am Client angeschlossen ist je nach Schaltstellung eine 0 oder eine 1 an den Server sendet. Das Senden der Daten (letzte 3 Zeilen im Client-Sketch) klappt mit client.println auch soweit, kann man auch im SM beobachten. Im Server muss ich aber die beiden Variablen, also Temperatur und Schaltzustand, weiterverarbeiten. Die beiden “Werte” werden aber in einem Zug übertragen und im Serversketch in die Variable “req” geschrieben.
Wie kann ich erreichen, das die Temperatur in den Server in eine Variable geschrieben wird und der Schaltzustand in eine andere?

Hier der Server-Sketch:

#include <ESP8266WiFi.h>


const char *ssid = "testserver";
const char *pass = "test4711";
const int httpPort = 80;
int  token= 3;                    //number of measuring device to ask
float wassertemp;
int fuellstand;

WiFiServer server(httpPort);
String req="";

void setup() {
  delay(500);
  Serial.begin(9600);
  Serial.println("Configuring AP");
  WiFi.mode(WIFI_AP);
  boolean result = WiFi.softAP(ssid,pass);
 
  if(result == true) Serial.println("Ready");
  else Serial.println("Failed!");
 
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {

Serial.printf("Stations connected to soft-AP = %d\n", WiFi.softAPgetStationNum());

WiFiClient client = server.available();

  if (client.connected()) {
    Serial.println("Send token");
    server.write("3");
  }

  if(client.connected()){
     req = client.readString();
     Serial.println(req);
     server.write("Message\n");
     Serial.println("Send");
  }
  else{
    Serial.println("No clients connected");
  }




wassertemp = (req.toInt());
Serial.print("Wassertemperatur: ");
Serial.println(wassertemp);
fuellstand = (req.toInt());
Serial.print("Fuellstand: ");
Serial.println(fuellstand);


delay(1000);
}

Und hier der Client-Sketch:

#include <ESP8266WiFi.h>
#include <DallasTemperature.h> //Siehe Hinweis oben, 
      //verwendet wird https://github.com/milesburton/Arduino-Temperature-Control-Library
#include <Base64.h>
#include <OneWire.h>
      
const char* ssid = "testserver";
const char* pass = "test4711";
const int Port = 80;
IPAddress host(192,168,4,1);
WiFiClient client;                         

#define ONE_WIRE_BUS D2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);

String req;

int inPin = 12;
String inPinValue;
int gpio_state = 0;


void setup() {

 pinMode(12, INPUT);      // Den digitalen Pin D6 als Eingang deklarieren.

 DS18B20.begin(); 
   
  delay(1000);
  Serial.begin(9600);
  Serial.print("Connecting to: ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);                     
  WiFi.begin(ssid, pass);                   
  while (WiFi.status() != WL_CONNECTED) {   
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());             

}

//Funktion um Innentemperatur zu ermitteln
float getTemperatur() {
 float temp;
 do {
   DS18B20.requestTemperatures(); 
   temp = DS18B20.getTempCByIndex(0);
   delay(100);
 } while (temp == 85.0 || temp == (-127.0));
 return temp;
}

//*********************************************************************
void loop() {

  if(WiFi.status() != WL_CONNECTED){
    Serial.println("reconnecting");
    WiFi.begin(ssid, pass);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
  }
  while(!client.connect(host, Port)){       
    Serial.println("\nCoonection failed");
    delay(500);
  }
  Serial.println("\nConnection successed");

char temperaturStr[6];
 float temperatur = getTemperatur();
 dtostrf(temperatur, 2, 1, temperaturStr);
 Serial.print("Temperatur: "); 
 Serial.println(temperaturStr); 

 if (digitalRead(inPin)==HIGH){
  inPinValue = "1";
} else {
  inPinValue = "0";
}
Serial.println(inPinValue);


  // reading from server
  if (client.connected()){
    req = client.readString();     // doesn't work
    Serial.println("reading...");
    Serial.println(req);
  }

//*********************************


   
   // sending to server
    client.println(temperaturStr);
    client.println(inPinValue);  
    delay(200);
     
}

Die letzten Zeilen im Server-Sketch habe ich selber geschrieben, aber das funktioniert halt nicht.
Im Anhang mal noch 2 Bilder vom SM Server und SM Client.

Ich hoffe, ich hab mich verständlich ausgedrückt. Nochmal in Kurzfassung, der Client soll zwei Variablenwerte per “client.print” getrennt von einander an den Server schicken und diese dann dort getrennt per client.read… eingelesen werden…
Danke für die Hilfe.

MfG
computerpap

Zur Lösung Deines Problems kann ich auf die Schnelle leider nichts beitragen. Mir ist im ersten Bild nur die fehlerhafte Schreibung aufgefallen:

successed succeeded

Gruß

Gregor

Nunja ... irgendwie interessiert sich niemand für Dein Problem oder es kennt sich keiner damit aus.

Obwohl ich weder die Geräte noch die Bibliotheken kenne, die Du verwendest, probiere ich's trotzdem mal. Vorweg musst Du aber noch etwas tun, und zwar den Code aufhübschen. Alles Überflüssige löschen, einheitliche Einrückungen und „ordentliche“ Klammerungen (zum Beispiel so, dass man erkennt, welcher Block sich in welchem befindet). Strg-T in der IDE ist schonmal ein sehr guter Startpunkt.

Damit Du ein paar Minuten Zeit hast, gehe ich jetzt eine rauchen :-)

Gruß

Gregor

Danke das du helfen willst. Kannst auch paar mehr rauchen, weil heute schaffe ich das mit den Code nicht mehr.

Ich habe das im Nachbarforum vor einigen Monaten mal vorgestellt (#32 und später noch eine Ergänzung).

Gruß Tommy

Danke Tommy, schau ich mir an.

Hallo
@gregorss, die beiden Sketche habe ich angehängt. Ich hoffe es ist einigermaßen übersichtlich.

@Tommy56, ich hab deine Sketche mal ausprobiert. Leider fehlt mir da noch Hintergrundwissen um alles zu verstehen. Definitiv ist es das, was ich machen will. Wenn ich das richtig interpretiere, sendest du Bytes hin oder her, die je nach Inhalt, als eine Art Trigger funktionieren. ZB wenn der Server 0x02 sendet, und der Client die 0x02 empfängt, schaltet die LED ein oder aus. Was ich nicht verstanden habe, wie du diese Bytes zusammensetzt, und wieder auseinander nimmst.

ESP_Server2.ino (2.22 KB)

ESP_Client2.ino (2.68 KB)

Ich hoffe, ich hab mich verständlich ausgedrückt. Nochmal in Kurzfassung, der Client soll zwei Variablenwerte per "client.print" getrennt von einander an den Server schicken und diese dann dort getrennt per client.read... eingelesen werden..

Hallo computerpap,

das "getrennt schicken - eingelesen" ist der falsche Ansatz. Du musst es zusammen schicken und zusammen empfangen. Beim schicken solltest du ein Trennzeichen zwischen beiden Variablen einfügen. So lässt es sich auf dem Server leichter teilen. Sollte es immer gleich lang sein, kannst du es auch einfach immer nach 4 Zeichen trennen.

Du kannst es auch wie Tommy schrieb, per Udp schicken. Das ist gar nicht so schwer. Dabei gilt oben gesagtes. Beispiel

Eine weitere Möglichkeit ist, deine Daten an die URL als Query String anzuhängen. Beispiel Auf dem Server kannst du den Query String mit server.hasArg() und server.arg() auswerten. Beispiel

Gruß Fips

Hallo Derfips Ich habe schon einige Beispiele mir angeschaut. Dort werden überall in einem Rutsch die Daten übertragen. Ich hatte mir schon fast gedacht, dass ich mit meiner Überlegung nicht ganz richtig liege. Der Hintergrund, warum ich es gerne so machen wollte, wie ich es beschrieben habe, ist, dass ich ja "nur" einen Temperaturwert und eine 0 oder 1 für den Schaltzustand eines Füllstandschalters von den Client an den Server schicken will. Ich dachte für diese Anwendung sind solche Beispiele wie sie von Tommy sind oder auch die ganze Geschichte mit Webserver oä. zu oversized. Außerdem sind meine Programmierkenntnisse auch noch recht übersichtlich. Vielleicht kannst du mir aber bitte mal erklären, warum man die Daten, egal bei welcher Methode, immer in einen Rutsch senden soll, das würde mich mal interessieren.

MfG computpap

Du kannst es natürlich einzeln Senden. Aber wenn die Temperatur 0 oder 1 ist, woher soll der Server wissen ob es Temperatur oder Schaltzustand ist. Du musst es auf dem Server auswerten können.

Gruß Fips

computerpap: Was ich nicht verstanden habe, wie du diese Bytes zusammensetzt, und wieder auseinander nimmst.

Das sind structs. hier ist ein Tutorial dazu.

Gruß Tommy

computerpap: @gregorss, die beiden Sketche habe ich angehängt. Ich hoffe es ist einigermaßen übersichtlich.

Ui, Du hast Dir echt Mühe gegeben! Zum näheren Angucken komme ich aber erst gegen Abend. Jetzt nur kurz zu structs:

Ein struct (eine Struktur) ist eine zusammengesetzte Variable. In Deinem Fall könnte der struct so aussehen:

struct messwerte
{
 float temperatur;
 boolean schaltzustand;
}

Auf die einzelnen Elemente der Struktur kannst Du dann beispielsweise so zugreifen: ``` float blablubb = messwerte.temperatur; boolean sz     = messwerte.schaltzustand; ``` (siehe PS)

Wichtig ist, dass die Definitionen der Struktur auf Client und Server identisch sind.

Ich hoffe, das hilft schonmal.

Gruß

Gregor

PS: Ups, ein Flüchtigkeitsfehler. Wenn Du die Struktur definiert hast, kannst Du eine entsprechende Variable anlegen:

messwerte foo;

Der Zugriff erfolgt dann so:

float temp = foo.temperatur;
boolean sz = foo.schaltzustand;

Nochmal hallo,

schön, dass die Sketche jetzt auf jeweils 1 A4-Seite passen. Bei einer Zigarette und frischer Luft (vor der kann man sich ja kaum schützen, wenn man auf dem Balkon sitzt) liest sich das echt bequem.

Wie ich das sehe, fehlen in beiden Sketchen lediglich struct-Definitionen und je eine Variable dieses Typs. Die kannst Du im Client befüllen und zum Server schicken. Dort nimmst Du das wie oben genannt auseinander und arbeitest damit.

Ich hoffe, das stimmt. Ich kenne das Zeug, mit dem Du zu tun hast, ja nicht.

Gruß

Gregor

PS: Befüllen z. B. so

req.temperatur=holdietemperatur();
req.schaltzustand=holdenschaltzustand();

Möglich wäre auch noch eine andere Herangehensweise: Der Server ermittelst im x-Sekunden-Abstand die Temperatur (oder mißt 10 Mal und bildet den Mittelwert) unabhängig von einer Anfrage und speichert das Ergebnis in einer globalen Variable.

Wenn die Anfrage kommt, wird nur der Inhalt dieser Variable (und der Schaltzustand) in die Struktur geschrieben und gesendet.

Gruß Tommy

Ich hatte heute leider noch keine Zeit weiter, um mich länger mit struct zu beschäftigen. Heute bekomme ich noch 2 Bücher über C bzw. C++,da hoffe ich, das ein oder andere Wissenswerte noch lesen zu können. Ich hab mal schnell den folgenden Code geschrieben, der sich nur auf den Client bezieht. Vielleicht könntet ihr ja mal drüber schauen, ob ich das so richtig verstanden habe.

//struct anlegen
struct messwerte {
  float temperature;
  int fuellstand;
};


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


}

void loop() {
  
  //Variable von struct anlegen
  struct messwerte sendeanserver;

  //An Server schicken
  Client.print(sendeanserver);
  }

Seh ich das so richtig, dass in sendeanserver, die Werte von temperature und fuellstand drin stehen?

Gruß computerpap

Wenn Du sie rein schreibst, stehen sie drin. Das hast Du aber nicht gemacht. Wie Du sie rein schreibst, wurde Dir bereits geschrieben.

Gruß Tommy

computerpap:   ...  //Variable von struct anlegen  struct messwerte sendeanserver;  ...

Das stimmt so nicht. Wenn Du die Struktur definiert hast, genügt

  messwerte sendeanserver;

um die Variable sendeanserver anzulegen.

Gruß

Gregor

Das Problem mit struct ist gelöst. Jetzt hab ich aber schon das nächste, wo ich nicht weiterkomme. Die Variable, die die ich von struct angelegt habe, kann nicht per client.println an den Server gesendet werden. client.println kann nur mit einfachen Datentypen wie string, int, float etc. umgehen. Ist es möglich, die struct-Variable in ein anderes Datenformat zu wandeln, welche dann auf Serverseite wieder zurück gewandelt werden kann?

struct messwerte
{
 char temperaturStr;
 int inPinValue;
};

messwerte sendeanserver;
  
client.println(sendeanserver);;

Hier die Fehlermeldung der IDE

Arduino: 1.8.1 (Windows 10), Board: "NodeMCU 1.0 (ESP-12E Module), 80 MHz, 115200, 4M (3M SPIFFS)"

C:\Users\Andreas\Documents\Arduino\ESP_Client2\ESP_Client2.ino: In function 'void loop()':

ESP_Client2:114: error: no matching function for call to 'WiFiClient::println(messwerte&)'

   client.println(sendeanserver);

                               ^

C:\Users\Andreas\Documents\Arduino\ESP_Client2\ESP_Client2.ino:114:31: note: candidates are:

In file included from C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Stream.h:26:0,

                 from C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/HardwareSerial.h:31,

                 from C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Arduino.h:246,

                 from sketch\ESP_Client2.ino.cpp:1:

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:79:16: note: size_t Print::println(const __FlashStringHelper*)

         size_t println(const __FlashStringHelper *);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:79:16: note:   no known conversion for argument 1 from 'messwerte' to 'const __FlashStringHelper*'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:80:16: note: size_t Print::println(const String&)

         size_t println(const String &s);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:80:16: note:   no known conversion for argument 1 from 'messwerte' to 'const String&'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:81:16: note: size_t Print::println(const char*)

         size_t println(const char[]);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:81:16: note:   no known conversion for argument 1 from 'messwerte' to 'const char*'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:82:16: note: size_t Print::println(char)

         size_t println(char);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:82:16: note:   no known conversion for argument 1 from 'messwerte' to 'char'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:83:16: note: size_t Print::println(unsigned char, int)

         size_t println(unsigned char, int = DEC);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:83:16: note:   no known conversion for argument 1 from 'messwerte' to 'unsigned char'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:84:16: note: size_t Print::println(int, int)

         size_t println(int, int = DEC);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:84:16: note:   no known conversion for argument 1 from 'messwerte' to 'int'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:85:16: note: size_t Print::println(unsigned int, int)

         size_t println(unsigned int, int = DEC);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:85:16: note:   no known conversion for argument 1 from 'messwerte' to 'unsigned int'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:86:16: note: size_t Print::println(long int, int)

         size_t println(long, int = DEC);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:86:16: note:   no known conversion for argument 1 from 'messwerte' to 'long int'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:87:16: note: size_t Print::println(long unsigned int, int)

         size_t println(unsigned long, int = DEC);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:87:16: note:   no known conversion for argument 1 from 'messwerte' to 'long unsigned int'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:88:16: note: size_t Print::println(double, int)

         size_t println(double, int = 2);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:88:16: note:   no known conversion for argument 1 from 'messwerte' to 'double'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:89:16: note: size_t Print::println(const Printable&)

         size_t println(const Printable&);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:89:16: note:   no known conversion for argument 1 from 'messwerte' to 'const Printable&'

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:90:16: note: size_t Print::println()

         size_t println(void);

                ^

C:\Users\Andreas\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.h:90:16: note:   candidate expects 0 arguments, 1 provided

exit status 1
no matching function for call to 'WiFiClient::println(messwerte&)'

MfG computerpap

Das steht in Dem Beispiel drin, dass ich Dir in #4 gegeben habe. Schau Dir den Slave an, der sendet eine Struktur.

Gruß Tommy

Man kann über das Printable Interface auch jede Klasse (bzw. structs) direkt mit Print drucken. Das ist für Anfänger aber nicht die beste Lösung

http://forum.arduino.cc/index.php?topic=484555.msg3307803#msg3307803

in printTo() werden die einzelnen Elemente des structs gedruckt. Danach kann man das struct an print() übergeben