Hallo,
ich habe zwei WEMOS D1 mini pro (version 1) im Einsatz. Der eine hat
einen DHT22 Sensor und der andere muss sich dort die Temperatur holen,
um davon abhängig ein Relais zu schalten.
Beide Geräte melden sich im selben WLAN Netz an. Über die jeweils
eigenen Webseiten kann ich das auch gut überprüfen - funktioniert also.
Auf dem DHT22 Server habe ich auch dafür gesorgt, dass der
Temperaturwert alleine übertragen wird (also unabhängig von der eigenen
Webseite). Funktioniert auch im Browser.
Nun möchte ich am Client die Werte erfragen und komme einfach nicht
dahinter, wie ich den "connection refused" Error wegbekomme und die
Daten übernehmen kann. Ich habe hier nur einen Teil des gesamten
Programm- Codes eingefügt in der Hoffnung, dass es noch halbwegs
verständlich ist und alle relevanten Libs enthalten sind.
Wie der Code funktionieren soll:
Wenn die Wifi- Verbindung steht, wird ein Ticker mit 15 Sekunden-
Laufzeit gestartet der lediglich ein Flag setzt, dass anschließend im
Loop()- Zweig ausgelesen wird. Von dort wird eine Funktion aufgerufen,
um einen http- Get- Aufruf zum Server zu starten. Zum Schluss wird das
Flag wieder zurückgesetzt.
Hmm ... irgendwie scheint die Frage aus dem Blickwinkel geraten zu
sein. Oder ist sie unter einer falschen Rubrik einsortiert? Falls ja,
bitte ich darum, sie umzuhängen.
Danke!
Schau dir https://www.arduino.cc/en/Reference/WiFiClient
Die benutzt den client falsch. Der erste Parameter muss ein Objekt von
der Klasse IPAddress sein:
> IPAddress server(192,168,178,96);> client.connect(server, 80)
Nachdem die Verbindung aufgebaut ist, sendest du den HTTP Request,
gefolgt von einer Leerzeile.
> client.println("GET /KorrigierteTemperatur HTTP/1.0");> client.println();
Dann wird der Server antworten:
1. HTTP/1.0 200 OK
2. Mehrere Header Zeilen, die du nicht brauchst
3. Eine Leerzeile
4. Das angeforderte Dokument
5. Der Server schließt die Verbindung
Was mir an dem Arduino Beispiel nicht so gut gefällt ist, dass es die
Zeilenumbrüche vermutlich nicht korrekt formatiert. Es sollte \r\n sein,
also besser:
> client.print("GET /KorrigierteTemperatur HTTP/1.0\r\n\r\n");
anstelle von println().
Falls dein Webserver das alte HTTP 1.0 nicht unterstützt, empfehle ich
dir Kapitel 10 aus
http://stefanfrings.de/mikrocontroller_buch/Einstieg%20in%20die%20Elektronik%20mit%20Mikrocontrollern%20-%20Band%202.pdf,
da erkläre ich HTTP 1.1
Hmm - hat eine Weile gedauert, bin einen großen Schritt weiter aber noch
nicht am Ende - Danke Stefan!
Ich habe meine Funktion folgendermaßen geändert:
In Zeile 4 kommt bereits ein "Connection: close"
danach kommen aber noch zwei Zeilen und in der Zeile 6 die eigentliche
Nutzantwort. Und nur durch die Abfrage, ob der Client noch verfügbar ist
und bereits geantwortet hat (Count > 0) schaffe ich es, aus der
Endlosschleife while (myclient.connected()){...} herauszukommen. Ohne
diesen else- Zweig, der Client bekommt den "Connection: close" offenbar
nicht mit, bleibt mein Code für ewig hier hängen. Mir stellt sich
deshalb auch die Frage, ob ich auf der Server-Seite alles richitg
gemacht habe.
Dort habe ich eine globale Variable
1
// Create an asynchronous web server on port 80.
2
AsyncWebServerserver(80);
definiert und im Setup() folgendermaßen auf die Client-Abfrage
reagiert:
Ist das richtig oder muss das dann auch anders aussehen? Kann hier auch
ein Grund dafür liegen, dass die while (myclient.connected()){...}-
Schleife nicht abgebrochen wird?
Danke noch mal - auch im Voraus :-) wenn du noch eine Idee hast!
hobbydunino schrieb:> myclient.print("GET /KorrigierterHeatIndex HTTP/1.0\r\n\r\n");> myclient.println();
Damit hast du insgesamt drei Zeilenumbrüche, da ist einer zu viel.
> In Zeile 4 kommt bereits ein "Connection: close"
Das heißt nicht, dass die Verbindung geschlossen wurde. Das ist nur ein
Text. Damit teilt der Server dem Client mit, dass er die Verbindung nach
der Antwort schließen wird.
Beim HTTP 1.1 Protokoll dürfte sie offen blieben. Aber das bringt andere
Komplexitäten mit sich.
Ich kenne mich mit Arduino nicht gut aus, deswegen kann ich dir nicht
sagen, ob du Server-Seitig alles richtig gemacht hast. Dein
Übertragungsprotokoll sieht jedenfalls gut aus.
Generell ist es keine gute Idee, schon als Anfang beide seiten der
Kommunikation selbst zu programmieren. Weil dann genau die Unsicherheit
entsteht, die du gerade hast. Installiere auf deinen PC irgendeinen HTTP
Server (ich mag den von Apache), von dem du Textdateien abrufst. Dann
bist du sicher, dass der Server OK ist.
Deinen eigenen Server kannst du gut mit dem Programm "curl" überprüfen.
Benutze den Parameter -v, dann gibt curl dir die ganze Kommunikation im
Klartext aus.
Der Server schickt ja auch mit der letzten Header-Zeile 2
Zeilenumbrüche. Das ist Teil des HTTP-Protokolls. Und danach kommen
genau die "Content-Length" an Bytes. Damit könntest du die
Endlos-Schleife in eine Schleife mit definiertem Ende umwandeln.
Dafür könnte man z.B. eine State-Machine nutzen:
Status 0 -> Lese Header-Zeilen, wenn eine Leer-Zeile kommt, dann Wechsel
in Status 1
Status 1 -> Lese solange Zeilen, bis Content-Length bytes empfangen
wurden, dann Wechsel in Status 2
Status 2 -> Fertig ;o)
Man könnte natürlich auch sowas, wie myclient.connected() noch mit
aufnehmen und bei einem disconnect den Status auf 3 -> Error setzen
( So eine Art Pseudo-Code, hab schon lange kein C mehr gemacht ;o)
status=0;
gelesen=0;
zulesen=0;
while (status<2) {
if (!myclient.connected()) {
status=2;
}
case( status ) {
0:
// code zum lesen einer Zeile
if( /* wenn zeile mit "Content-Length:" anfängt */ ) ) {
zulesen=/* String nach int konvertieren */ }
if( zeilenlänge = 0 ) { status=1; }
break;
1:
// code zum Lesen des Content
gelesen += /* Länge der aktuellen Zeile */
if( gelesen == zulesen ) { status = 2; }
break;
}
}
// Abhängig davon, ob status == 1 oder == 2 geht es dann weiter mit
// Fehlerbehandlung oder mit sonstigem Code
Der Content-Length Header ist bei HTTP 1.0 Protokoll optional. Deswegen
würde ich mich nicht darauf verlassen, dass er vorhanden ist.
Selbst wenn er vorhanden ist, kann die Verbindung vorzeitig abbrechen.
Das darf nicht dazu führen, dass sich der Client in einer endlosen
Warteschleife aufhängt.
Soweit ich sehe, passiert das bei der while Schleife des TO (und bei der
von MagIO2) auch nicht, also alles gut. Ich wollte nur mal drauf
hinweisen, denn den Fehler habe ich selbst mal gemacht. Er fiel erst
Wochen nach der Inbetriebnahme auf und stiftete daher schlechte Laune.
Danke für Euer Feedback. Habe die dritte Leerzeile beim Serveraufruf
entfernt. Ob es was damit zu tun hat oder nicht - egal jetzt geht er
nicht mehr in die Endlosschleife. Somit funktioniert der Code jetzt
erstmal so weit, dass ich den Temperaturwert herausfiltern und damit
weiterarbeiten kann. Ganz herzlichen Dank noch mal - auch dass ihr Euch
am Wochenende darum kümmert!!
Du könntest für den Zweck auf ganz auf TCP/HTTP verzichten.
Leg deinen 15s Timer auf dem Server an und sende deinen Temperaturwert
per UDP an die IP des Client. Dann bekommst du am Client genau das eine
Paket was ausschließlich deine Nutzdaten enthält.
Sascha