Arduino client,php-apache server

Salve a tutti ,sto cercando di realizzare un sistema client server col protocollo tcp usando i socket,dove arduino rappresenta il mio client(utilizzo un ethernet shield) e ho un server apache(in locale) su cui è caricata una pagina php,non essendo molto esperto di reti ed essendomi da poco affacciato a questo mondo vorrei porre qualche domanda così da poter risolvere il problema sorto grazie all'aiuto di tutti voi.
Il codice di per se funziona o almeno mi sembra,la connessione viene stabilita,riesco a trasmettere dei dati e a ricevere risposta dal server,il problema nasce quando però osservo che eseguita la connessione posso scambiare un unico messaggio tra client e server,credo che il problema sia lato php in quanto instaura la connessione,fa il bind ecc ma essendo abbastanza lineare come codice esce subito riinviato il messaggio.
Mi sono venute in mente due soluzioni anche se non credo siano effettivamente realizzabili ossia refreshare la pagina php appena inviata la risposta all'arduino oppure chiamare la pagina php dal client in qualche modo a me sconosciuto.
Posto il codice da me scitto così da poter essere tutto più chiaro,Ringrazio tutti quanti in anticipo per l'aiuto fornito.
Client :

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };//definizione mac(in teoria primi 3 byte produttore e secondi 3 identificativo scheda)
//indirizzo server web (locale)
byte server[] = {192, 168, 1, 233}; //da cambiare ogni volta a meno che non lo fisso sul router

byte ip[] = {192, 168, 1, 234};

EthernetClient client;//qui inizializzo l'oggetto client
String leggoStringa;
void setup() {
  Serial.begin(9600);
  Ethernet.begin(mac, ip); //assegno al clent un ip e un mac che sono quelli attuali
  //così sono sicuro che non devo cercare robe strane
  if (client.connect(server, 80))
    //è la porta del servizio https
    //o del socket devo capire bene
  {
    Serial.println("connesso");
  }
  else {
    Serial.println(" non connesso");

  }
  
}
void loop() {
  if (client.connected()) {
    //chiamo le funzioni che mi servono
    //Serial.println("ok");//qui funge se lo attacco al router come ovvio che sia
    client.println("1000");
  //Serial.println("ok");
    if (client.available()) {
      char c = client.read();
      leggoStringa.concat(c);
    }
    Serial.println(leggoStringa);
  }
}

Server:

<?php
// set some variables
$host = "192.168.1.233";
$port = 80;
// don't timeout!
set_time_limit(0);
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");
// start listening for connections,il secondo parametro indica che non mette in attesa più di due client
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");

// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming connection\n");
// read client input
$input = socket_read($spawn, 1024) or die("Could not read input\n");
$response=0;
include "Connessione.php";//è un file esterno al mio db in locale 
	$sql1 = "SELECT Codice_numerico from `Utenti`";
	//esegue la query in caso di errore me lo scrive
	$result = mysqli_query($link, $sql1) or die(mysqli_error($link));
	// While a row of data exists, put that row in $row as an associative array
	//lo fa per ogni riga e quindi devo controllare ogni riga
	//se alla fine esce true allora vuol dire che la persona può entrare
	while ($row = $result->fetch_assoc()) {
		if ($row["Codice_numerico"]==$input) {
		  $response=1;
    }
}
mysqli_close($link);//interrompo la connessione col db
socket_write($spawn, $response, strlen ($response)) or die("Could not write response\n");
// close sockets
socket_close($spawn);
socket_close($socket);
?>

Perché è cosi che funziona: il client (ovvero Arduino) fa una richiesta, il server risponde e fine della connessione.

Per mantenere una connessione attiva tra client e server, ci sono alcune "tecnologie web" specifiche tra cui senza dubbio WebSocket è quella più diffusa e supportata. Sicuramente online troverai qualche esempio di implementazione con PHP

ti ringrazio,poi ero riuscito a far funzionare il tutto ricaricando la pagina ogni 10 secondi,ma voglio a questo punto indagare anche sui web-socket,se servisse credo che proverò a cambiare linguaggio server,stavo pensando di usare a mali estremi il python che da quanto ho letto è molto supportato sotto il punto di vista dei websocket,anche se per php ho trovato ratchet,aggiorno tutti con la soluzione che troverò ,o con i problemi che verranno,grazie per l'aiuto

Perdonami, ma è davvero uno dei modi più brutti che ci siano... sa molto di pagine web degli anni '90 :rofl:

Secondo me riesci senza problemi anche con PHP puro. Non sono un esperto di PHP, ma se riesco questa sera provo a darci uno sguardo anche io.

Se vuoi sperimentare altre soluzioni dai uno sguardo anche a NodeJS.
Non servirebbe nemmeno tenere online il server Apache a quel punto...

si concordo che è molto brutto,se non riesco a implementare il tutto entro il 20,mi toccherà lasciare il codice offline che ho fatto,ma comunque mo mi metto sotto e cerco di risolvere.
Ieri cercando in giro come avevo detto ho trovato ratchet e tale libreria GitHub - brandenhall/Arduino-Websocket per arduino, finito con il php con cui sono più diciamo pratico vorrei vedermi node.js,l'idea per l'estate era capire lui e react ma diciamo ho bisogno di uno studio un pò più approfondito per capire come funzionano,e avendo una scadenza devo un pò arrangiarmi,finita sta cosa sicuro cercherò di capire come funzionano,grazie per l'aiuto

Scusate, non sono esperto di roba web, ma...
lato Arduino hai un programma che fa la connessione solo nel setup.
Se si connette, la loop farà 1 lettura e poi naturalmente il tutto finisce.
Mi pare che il codice dovrebbe stare tutto nel loop() e naturalmente non basta spostare il pezzo da setup. Nel loop bisognerà tentare la connessione, se va okay mandi richiesta, altrimenti ogni tot tempo puoi riprovare a fare la connessione (esempio ogni 5 secondi)
Oppure non ho capito quel che vuoi fare

in realtà non credo sia così(potrei dire tranquillamente una cazzata quindi se l'ho detta correggetemi),ossia il fatto è che manca la chiusura della connessione nel loop che effettivamente dovrebbe venir chiusa dal server ,quindi in teoria la connessione rimane sempre attiva,il problema è lato server in quanto la pagina php non può essere ricaricata in continuazione,salvo metodo orribile da me adoperato come citato prima,perciò per avere uno scambio di dati continuo necessito, come fatto intuire da cotestantnt di un websocket il quale apre una connessione continua che non si interrompe al primo permittimi di dire botta e risposta.

No, non è così: una richiesta http muore nel momento in cui il server ha fatto quello che deve, poi anche se il socket rimane aperto, devi comunque fare una nuova richiesta ripetendo la procedura.
Arduino non si comporta come il browser facendo il refresh della pagina in automatico.

React è un framework JavaScript piuttosto complesso da imparare (stessa cosa per Angular), forse ti conviene iniziare da qualcosa con una curva di apprendimento più rapida come ad esempio vue.js il quale è un sistema che si pone a metà strada tra angular e react come principio di funzionamento.

Soprattutto quello che hai scritto lato pc è una semplice pagina web (in php) , non un webservice.
Meglio sarebbe scrivere lato server un webservice.

ti ringrazio per la dritta, cercherò di capire anche cos'è e come implementare un webservice se riesco.

Forse conviene fare qualche passo indietro... probabilmente è meglio se ci dai indicazioni su che cosa vorresti fare, ovvero sull'obiettivo prefissato che non è molto chiaro, piuttosto che nel modo che hai cercato di usare fino ad ora.

Quando parlavi di React nel post precedente, nella mia mente purtroppo ho dato per scontato che volessi impararlo per altre ragioni e non per sviluppare quest'applicazione specifica dove è del tutto inutile.

React, cosi come gli altri tool che ti ho citato, sono dei framework Javascript fantastici per realizzare dei front-end "reactive" (ovvero, detto grossolanamente, un'interfaccia utente che si aggiorna in automatico al variare dei dati rappresentati) e praticamente inutili invece per implementare dei web service come ti ha giustamente suggerito @nid69ita

allora il progetto da me svolto in realtà è diviso in 2 parti,una offline che vi linko(c'è la spiegazione sul progettino da fare con un servo ecc) Problema microservo SG90 ,la seconda parte è invece evitare di memorizzare i codici sull'arduino e fare un controllo di questi online con un server apache e quindi utilizzare il php,in pratica tutta la cosa che sto facendo mo è per capire come far funzionare la connessione tra arduino e il server in maniera continua.
Se ho voglia e tempo soprattutto nessuno mi vieta di mettere le mani in pasta e giocare con altra roba ragionando sul database che ho fatto,che è semplice ma mi da dei possibili dati interessanti,ora però la cosa che mi preme è la domotica se così la posso chiamare del sistema, sto facendo il progetto per una tesi triennale in ingegneria meccanica poi quindi non deve nemmeno essere iper elaborato,mi è preso solo il pallino che voglio imparare la programmazione web da metà agosto fino ad ottobre in quanto non ho lezioni e apparte lavorare non ho molto di meglio da fare,mi scuso per l'eventuale poca chiarezza nei messaggi precedenti e ringrazio nuovamente tutti delle attenzioni che mi state dando

Secondo me stai facendo tutto molto più complicato del necessario.
Non hai bisogno di mantenere una connessione permanente con il server per controllare se un codice è abilitato oppure no.

Quando inserisci il codice, prepari una richiesta da inviare al server contenente il codice appena inserito, il server la elabora in funzione dei dati memorizzati nel database e ti risponde si oppure no.

All'inserimento successivo ripeti la procedura nello stesso identico modo.

allora oggi ho riflettutto su quello che mi avevi scritto quindi ho provato a modificare codice arduino e php te li posto:

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };//definizione mac(in teoria primi 3 byte produttore e secondi 3 identificativo scheda)
//indirizzo server web (locale)
byte server[] = {192, 168, 1, 233}; //da cambiare ogni volta a meno che non lo fisso sul router

byte ip[] = {192, 168, 1, 234};
String strURL = "";
EthernetClient client;//qui inizializzo l'oggetto client
String leggoStringa;
void invioCodice() {
  //creo l'url utilizzando una stringa
  strURL = "GET /tesi/ServerPHP.php?Code="; //devo modificare nome pagina e il nome della variabile dopo ?
  strURL += "1000";
  //strURL += " HTTP/1.1";
  //invio la richiesta al server
  client.println(strURL);
  client.println("Host: 192.168.1.233");
}
void setup() {
  Serial.begin(9600);
  Ethernet.begin(mac, ip); //assegno al clent un ip e un mac che sono quelli attuali
  //così sono sicuro che non devo cercare robe strane
  if (client.connect(server, 80))
  {
    Serial.println("connesso");
  }
  else {
    Serial.println("non connesso");
  }
}
void loop() {
  leggoStringa = "";
  if (client.connect(server, 80))
  {
  if (client.connected()) {
    //chiamo le funzioni che mi servono
    //Serial.println("ok");//qui funge se lo attacco al router come ovvio che sia
    //client.println("2000");
    Serial.println("fin qui ci sto");
    invioCodice();
    Serial.println("ok");
    if (client.available()) {
      Serial.println("ok");
      char c = client.read();
      leggoStringa.concat(c);
      
    }
    Serial.println(leggoStringa);
    Serial.println();
    Serial.println("Connection: close");
    client.stop();

  }
 }else {
    Serial.println("non connesso");
  }
}
<?php
// set some variables
$host = "192.168.1.233";
$port = 80;

if(isset($_GET['Code'])){
$input=$_GET['Code'];
echo $input;
// don't timeout!
set_time_limit(0);
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");
// start listening for connections,il secondo parametro indica che non mette in attesa più di due client
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");

// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming connection\n");

$response=0;
include "Connessione.php";
	$sql1 = "SELECT Codice_numerico from `Utenti`";
	//esegue la query in caso di errore me lo scrive
	$result = mysqli_query($link, $sql1) or die(mysqli_error($link));
	// While a row of data exists, put that row in $row as an associative array
	//lo fa per ogni riga e quindi devo controllare ogni riga
	//se alla fine esce true allora vuol dire che la persona può entrare
	while ($row = $result->fetch_assoc()) {
		if ($row["Codice_numerico"]==$input) {
		  $response=1;
    }
}
echo $response;
mysqli_close($link);//interrompo la connessione col db
socket_write($spawn, $response, strlen ($response)) or die("Could not write response\n");
// close sockets
socket_close($spawn);
socket_close($socket);
/*
Imposto un refresh della pagina corrente dopo 10 secondi
*/
/*echo "sto per lanciare il rederect";
$curpage = $_SERVER['PHP_SELF'];
header('Refresh: 10; url=' . $curpage);
*/
}
?>

ho provato a vedere se l'insieme funzionava,la connessione segna che viene effettuata ma se non apro la pag e inserisco la get manualmente non entra nell'isset,inoltre anche se l'isset va a buon fine ,aspetta il bind come è logico che sia ,ma poi non capisco perchè il write non va o l'arduino non riceven dati anche se il risultato della variabile response è 1
credo di non aver capito se non è questa la metodica come interrogare la pagina php da arduino,grazie in anticipo della risposta

Questa funzione non va bene: una richiesta HTTP deve concludersi con la versione del protocollo ovvero la riga che hai commentato (per quale ragione?).

A seguire il client deve inviare tutti gli headers richiesti e/o necessari e nel tuo caso si tratta solo dell'host (che sarebbe meglio creare dinamicamente perchè l'IP potrebbe cambiare).

Quando hai inviato tutti gli headers, l'ultima riga deve essere un client.println() vuoto, cosa che nel protocollo HTTP sta ad indicare che non ci sono più headers da trasmettere.

Prova cosi:

void invioCodice(const char* codice) {
  //creo l'url utilizzando una stringa
  strURL = "GET /tesi/ServerPHP.php?Code=";
  strURL += codice;
  strURL += " HTTP/1.1";
  //invio la richiesta al server
  client.println(strURL);
  client.println("Host: 192.168.1.233");
  client.println("Connection: close");
  client.println();
}

e nel loop ovviamente alla funzione invioCodice() devi passare il codice da verificare. Scritta cosi la funzione te la puoi "riciclare" nell'altro sketch e la varibile da passare sarà ovviamente quella composta con il tastierino numerico keyInsert

invioCodice("1234"); 

ok stamattina ho fatto un paio di prove ma nulla,ho provato sia con questa metodica che col tcp senza passare dati con la GET(ossia richiamo la pagina allo stesso modo senza inviare nulla) ma nulla,è come se non entrasse nella pagina(o comunque non comunica i dati) anche se la connessione viene stabilita.
Mo vedo di smanettare un'altro pò ricontrollando e cercando altre vie così che possa funzionare

ok sono riuscito ad ottenere una risposta decente(ho ritrovato un post sul forum che mi ha dato la soluzione arduino riceve risposte da php), ho dovuto proprio cambiare logica del php però,mo cerco di implementare tutto sul progetto originale,intanto però metto il codice php e arduino per chiunque si chieda come fare, PS avevi ragione cotestatnt mi ero incasinato e basta,grazie ancora.

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };//definizione mac(in teoria primi 3 byte produttore e secondi 3 identificativo scheda)
//indirizzo server web (locale)
byte server[] = {192, 168, 1, 233}; //da cambiare ogni volta a meno che non lo fisso sul router

byte ip[] = {192, 168, 1, 234};
String strURL = "";
EthernetClient client;//qui inizializzo l'oggetto client
String leggoStringa;
void invioCodice() {
  //creo l'url utilizzando una stringa
  strURL = "GET /tesi/ServerPHP.php?Code="; //devo modificare nome pagina e il nome della variabile dopo ?
  strURL += "1000";
  strURL += " HTTP/1.1";
  //invio la richiesta al server
  //Serial.println(strURL);
  client.println(strURL);
  client.println("Host: 192.168.1.233");
  client.println("Connection: close");
  client.println();
}
void setup() {
  Serial.begin(9600);
  Ethernet.begin(mac, ip); //assegno al clent un ip e un mac che sono quelli attuali
  //così sono sicuro che non devo cercare robe strane
  if (client.connect(server, 80))
  {
    Serial.println("connesso");
  }
  else {
    Serial.println("non connesso");
  }
}
void loop() {
  leggoStringa = "";
 
  if (client.connected()) {
    //chiamo le funzioni che mi servonol router come ovvio che sia 
    //Serial.println("ok");//qui funge se lo attacco a
    //Serial.println("fin qui ci sto");
    invioCodice();
    while (client.available()) {
      //Serial.println("ok");
      char c = client.read();
      leggoStringa.concat(c);
    }
    Serial.println(leggoStringa);    
    //client.stop();
    delay(1000);
 
  }
  }

PHP

<?php
// set some variables
$host = "192.168.1.234";
$response=0;
$input=$_GET['Code'];
include "Connessione.php";
	$sql1 = "SELECT Codice_numerico from `Utenti`";
	//esegue la query in caso di errore me lo scrive
	$result = mysqli_query($link, $sql1) or die(mysqli_error($link));
	// While a row of data exists, put that row in $row as an associative array
	//lo fa per ogni riga e quindi devo controllare ogni riga
	//se alla fine esce true allora vuol dire che la persona può entrare
	while ($row = $result->fetch_assoc()) {
		if ($row["Codice_numerico"]==$input) {
		  $response=1;
    }
}
echo "risposta=".$response;
//echo '<iframe src="http://'.$host.'?accesstatus="'.$response.'"></iframe>';
?>

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