Ciao a tutti,
ho creato una pagina php per inviare dati raccolti con Arduino a un database mysql utilizzando il metodo GET.
La pagina php funziona, se eseguita in un browser salva correttamente i dati.
Riscontro però problemi lato Arduino, in particolare uso un ESP8266 NodeMCU.
Riporto di seguito la parte di codice relativa all'invio dei dati, non capisco per quale motivo non produce alcun risultato:
Intendi lato php immagino?
Prova a leggere anche la risposta del server e stamparla sul monitor seriale cosi hai qualche elemento in più per capire cosa succede.
Stai inviando questa richiesta al server senza connessione???
Ciao @cotestatnt,
ti ringrazio per la risposta.
Lato php la pagina funziona, se la eseguo dal browser si caricano tutti i dati nel database mysql.
Come devo fare per leggere la risposta del server sul monitor seriale? Sarebbe molto utile per capire cosa non funziona.
Comunque avendo testato che lato php è tutto ok, volevo capire se la parte di codice che ho postato presenta problemi o se è corretta, in modo da approfondire se il problema è quindi nella connessione.
Intendevo, la chiamata GET fatta dall'esp produce effetti sul server cosi come accade con il browser oppure non succede proprio nulla?
Per quanto riguarda la risposta del server devi leggere la risposta che ti invia.
Gli esempi inclusi sono il punto di partenza, comunque di base dopo aver inviato la richiesta aggiungi questo (preso paro paro dall'esempio WiFiClient.ino
// wait for data to be available
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
delay(60000);
return;
}
}
// Read all the lines of the reply from server and print them to Serial
Serial.println("receiving from remote server");
// not testing 'client.connected()' since we do not need to send data here
while (client.available()) {
char ch = static_cast<char>(client.read());
Serial.print(ch);
}
Non succede proprio nulla, come se la pagina non venisse proprio eseguita.
Ho provato a riportare il codice da te suggerito dopo la mia richiesta ma non ricevo alcuna risposta, non viene visualizzato niente sul serial monitor.
La connessione c'è, visto che invio anche i dati su Thing Speak e funziona senza problemi.
Non capisco dove sta il problema.
Ciao @begins
Sei riuscito a trovare l'inghippo poi?
Ho provato a simulare in un server locale la tua chiamata GET partendo dall'esempio base incluso nell'IDE che ti allego.
Il problema secondo me è che di default PHP blocca le chiamate che arrivano dall'esterno e quindi devi aggiungere l'header:
Access-Control-Allow-Origin: *
Nell'esempio ho dovuto mettere come host l'indirizzo IP del PC dove gira il server locale perché l'ESP non sarebbe in grado di risolvere il nome "mysite.test" altrimenti.
Se il tuo server è online, ovviamente devi metterci l'hostname corretto.
/*
This sketch establishes a TCP connection to a "quote of the day" service.
It sends a "hello" message, and then prints received data.
*/
#include <ESP8266WiFi.h>
const char* ssid = "xxxxxxxxxx";
const char* password = "xxxxxxxxxx";
const char* host = "192.168.2.81";
const uint16_t port = 80;
void setup() {
Serial.begin(115200);
// We start by connecting to a WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
/* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default,
would try to act as both a client and an access-point and could cause
network-issues with your other WiFi-devices on your WiFi-network. */
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
Serial.print("connecting to ");
Serial.print(host);
Serial.print(':');
Serial.println(port);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("connection failed");
delay(5000);
return;
}
// This will send a string to the server
Serial.println("sending data to server");
if (client.connected()) {
float temperatura_media = 25.6;
float pressione_media = 1008.2;
int umidita_media = 45;
int pm10_media = 350;
String var="temperatura=" + String(temperatura_media) + "&pressione=" + String(pressione_media) + "&umidita=" + String(umidita_media) + "&pm10=" + String(pm10_media);
String url = "GET /aggiungi.php?" + var + " HTTP/1.1";
client.println(url);
client.println("Host: mysite.test");
client.println("Access-Control-Allow-Origin: *");
client.println("Connection: close");
client.println();
}
// wait for data to be available
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
delay(60000);
return;
}
}
// Read all the lines of the reply from server and print them to Serial
Serial.println("receiving from remote server");
// not testing 'client.connected()' since we do not need to send data here
while (client.available()) {
char ch = static_cast<char>(client.read());
Serial.print(ch);
}
// Close the connection
Serial.println();
Serial.println("closing connection");
client.stop();
delay(300000); // execute once every 5 minutes, don't flood remote service
}
Ciao @cotestatnt !
Ho seguito alla lettera i tuoi consigli: ho aggiunto nella pagina php l'header come da te suggerito.
header("Access-Control-Allow-Origin: *");
Ho caricato il tuo codice sull'esp e l'ho eseguito ricevendo in risposta sul monitor seriale quanto segue:
WiFi connected
IP address:
192.168.3.127
connecting to www.xxxxxx.it:80
sending data to server
receiving from remote server
HTTP/1.1 301 Moved Permanently
Server: aruba-proxy
Date: Thu, 13 May 2021 19:49:30 GMT
Content-Type: text/html
Content-Length: 184
Connection: close
Location: https://www.xxxxxxxx.it/aggiungi.php?temperatura=25.60&pressione=1008.20&umidita=45&pm10=350
X-ServerName: ipvsproxy51.ad.aruba.it
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>aruba-proxy</center>
</body>
</html>
closing connection
Purtroppo però non vengono ancora caricati i dati sul database mysql.
Almeno riesci a leggere la risposta del server... Un passetto in avanti.
Ottieni 301 probabilmente perché stai usando una connessione http mentre il tuo server è https e fa un redirect automatico.
Dovresti usare un oggetto WiFiClientSecure sulla porta 443.
Guarda gli esempi come punto di partenza.
Se non vuoi caricare il certificato, aggiungi l'istruzione client.setInsecure(true) prima di collegarti.
Si un passo avanti, e ti ringrazio perché io non avrei mai capito fosse un problema legato a questo.
Stasera provo a fare qualche ricerca in rete in merito al WiFiClientSecure, ma è un argomento per me nuovo, se per caso conosci già qualche link con un esempio utile scrivilo pure.
Ciao @cotestatnt
Ho seguito il tuo consiglio, e ho quindi modificato il codice utilizzando l'oggetto WiFiClientSecure e inserendo l'istruzione client.setInsecure();.
Il codice, che riporto di seguito nel caso possa essere utile a qualcun altro, ora funziona.
#include <ESP8266WiFi.h>
const char* ssid = "";
const char* password = "";
const char* host = "www.xxxxxxxxx.it";
const uint16_t port = 443;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
Serial.print("connecting to ");
Serial.print(host);
Serial.print(':');
Serial.println(port);
WiFiClientSecure client;
client.setInsecure();
if (!client.connect(host, port)) {
Serial.println("connection failed");
delay(5000);
return;
}
Serial.println("sending data to server");
if (client.connected()) {
float temperatura_media = 25.6;
float pressione_media = 1008.2;
int umidita_media = 45;
int pm10_media = 350;
String var="temperatura=" + String(temperatura_media) + "&pressione=" + String(pressione_media) + "&umidita=" + String(umidita_media) + "&pm10=" + String(pm10_media);
String url = "GET /aggiungi.php?" + var + " HTTP/1.1";
client.println(url);
client.println("Host: www.xxxxx.it");
client.println("Access-Control-Allow-Origin: *");
client.println("Connection: close");
client.println();
}
// wait for data to be available
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
delay(60000);
return;
}
}
// Read all the lines of the reply from server and print them to Serial
Serial.println("receiving from remote server");
// not testing 'client.connected()' since we do not need to send data here
while (client.available()) {
char ch = static_cast<char>(client.read());
Serial.print(ch);
}
// Close the connection
Serial.println();
Serial.println("closing connection");
client.stop();
delay(300000); // execute once every 5 minutes, don't flood remote service
}
Ovviamente in questa modalità non si utilizza alcun certificato di sicurezza.
Non me ne intendo quindi chiedo, cosa comporta questo?
E' un problema se viene utilizzata la connessione per recuperare i dati da una stazione meteo?
In caso, per procedere utilizzando un certificato, è molto più complicato il codice?
In questa modalità in poche parole l'esp "si fida" del server che gli dice chi dovrebbe essere ovvero il tuo www.xxxxxx.it senza fare alcuna verifica sul certificato fornito.
Lo scambio dei dati è comunque cifrato perché https sulla porta 443 ed è già un grande passo in più rispetto ad http dove viaggia tutto in chiaro. Il rischio più importante è il cosiddetto "man in the middle" ovvero qualcuno che finge di essere il tuo server; non avresti alcun modo per verificare.
Oggettivamente le possibilità che questo accada per "rubare" qualche lettura di temperatura e pressione le vedo davvero minime se non nulle..