client • Le blog d'Eskimon – Bien choisir son serveur d impression

Commençons lentement à découvrir ce bouclier en utilisant notre Arduino comme

client

.
Dans ce chapitre, nous découvrirons comment amener notre Arduino à se rendre sur un site Web pour en obtenir des informations.

Ici, nous allons interroger un site Web, mais cela aurait très bien pu être un autre service, sur un autre port (vous l'aurez compris)

Afin de comprendre cela, je vous propose tout d'abord quelques explications sur le protocole HTTP et comment se déroule un échange de données (requête + réponse).

Ensuite, nous verrons comment installer le bouclier et le rendre accessible au monde extérieur.

Enfin, nous mettrons tout en œuvre pour faire une simple demande sur un moteur de recherche.

Pour finir, je vous propose un petit exercice qui vous permettra de voir un cas d'utilisation: la "surveillance" d'un serveur.

Sommaire

Client HTTP et requêtes

Examinons rapidement la notion de client et, surtout, découvrons en détail en quoi consiste exactement une demande HTTP.

Que fait un client?

Le rôle du client est finalement assez simple. Son but sera de rechercher des informations pour les afficher à un utilisateur ou effectuer une action spécifique. De manière générale, le client sera celui qui traite les informations que le serveur envoie.

Prenons l'exemple du navigateur Web. C & # 39; est un

client

. Lorsque vous l'utilisez, vous générez

demandes

aux serveurs et ils enverront alors beaucoup d'informations (la page Web). Le navigateur les traitera ensuite pour vous les afficher sous une forme agréable fournie par le développeur Web.

Enfin, il est simple d'être client, il suffit de demander des choses et d'attendre qu'elles arrivent
:)
!

Les termes «client» et «serveur» (et même «demande») sont très bien choisis car ils illustrent très bien les mêmes rôles que leur équivalent «dans la vraie vie».

Qu'est-ce qu'une requête HTTP?

Les requêtes HTTP sont de plusieurs types. Les plus classiques sont sûrement GET et POST, mais on trouve aussi PUT, DELETE, HEAD … Pour faire simple, on ne s'intéressera qu'au premier car c'est celui qui est utilisé la plupart du temps!

Programme

Dans la spécification du protocole HTTP, nous apprenons que GET nous permet de demander une ressource en lecture seule. Nous aurons simplement besoin de spécifier une page cible puis le serveur HTTP de cette page nous enverra la ressource ou un code d'erreur en cas de problème. Vous pouvez passer des arguments / options à la fin de l'adresse que vous interrogez pour demander des choses plus spécifiques au serveur.

Par exemple, si vous êtes sur la page d'accueil de Google et que vous recherchez "Arduino", votre navigateur fera la demande suivante:

OBTENIR / rechercher? Q = Arduino HTTP / 1.0

. Il interroge donc la page principale "/" (root) et envoie l'argument "search? Q = arduino". Le reste définit le protocole utilisé.

accueil

Une fois la demande effectuée, le serveur interrogé vous enverra une réponse. Cette réponse peut être décomposée en deux choses: l'en-tête et le contenu. Nous pourrions comparer cela à un envoi de colis. L'en-tête aurait les informations sur le package (destinataires, etc.) et le contenu est ce qu'il y a à l'intérieur du package.

Typiquement, dans une réponse minimaliste, nous lirons les informations suivantes:

  • Le code de réponse de la demande (200 si tout s'est bien passé);

  • Le type MIME du contenu renvoyé (

    texte / html

    dans le cas d'une page Web);

  • Une ligne vide / vide;

  • Les contenus.

Les deux premières lignes font partie de l'en-tête, puis viendra le contenu.

Si vous souhaitez rechercher des informations, vous le ferez généralement dans le contenu.

Utiliser le bouclier en tant que client

Maintenant que nous en savons un peu plus, nous allons pouvoir faire des demandes et aller interroger le monde …

Préparation minimale

Pour commencer, nous devrons configurer notre module Ethernet pour qu'il fonctionne correctement. Pour cela, nous devrons lui donner une adresse MAC et une adresse IP (qui peuvent être automatiques, nous y reviendrons). Nous utiliserons 4 variables différentes:

  • Un étalage de

    octet

    (ou char) pour les 6 octets de l'adresse MAC;

  • Un objet

    Adresse IP

    avec l'adresse IP attribuée au module;

  • Un objet

    EthernetClient

    que nous utiliserons pour faire la communication;

  • Une chaîne de caractères représentant le nom du serveur à interroger.

L'adresse MAC doit normalement être inscrite sur un autocollant au dos de votre bouclier (sinon inventez-en un!)

De manière programmatique, nous aurons les variables ci-dessous.


#comprendre 
#comprendre 











octet mac[] =  0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E ;

Adresse IP ip((192,168,0,143);

Client EthernetClient;

réservoir serveur[] = "leserveur.com"

Démarrer le bouclier

Maintenant que nous avons nos variables, nous pouvons commencer notre bouclier dans le

installer ()

. Pour ce faire, il suffit d'appeler une fonction bien nommée:

commencer ()

, oui, comme pour le canal série! Cette fonction prendra deux paramètres, l'adresse MAC et l'adresse IP à utiliser. C'est aussi simple que ça!


#comprendre 
#comprendre 











octet mac[] =  0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E ;

Adresse IP ip((192,168,0,143);

Client EthernetClient;

réservoir serveur[] = "lost.com"

néant installer () 

Serial.begin (9600);


Ethernet.begin (mac, ip);

retard (1000);

C'est simple, non?

DHCP

Si vous bricolez à la maison, il est très probable que vous utilisiez un routeur ou votre box Internet. Très souvent, ces derniers ont la fonction DHCP activée par défaut. Cette technologie permet de donner automatiquement une adresse IP à tous les équipements qui se connectent au réseau. Ainsi, pas besoin de le faire manuellement!

Nous pouvons donc modifier notre script d'initialisation pour en tenir compte.


#comprendre 
#comprendre 











octet mac[] =  0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E ;

Adresse IP ip((192,168,0,143);

Client EthernetClient;

réservoir serveur[] = "lost.com";

néant installer() 

Serial.begin (9600);

  réservoir erreur = 0;

erreur = Ethernet.begin (mac);

  si (erreur == 0) 
Serial.println ("Configuration avec IP fixe ...");


Ethernet.begin (mac, ip);

Serial.println ("Init ...");

retard (1000);
Serial.println ("Prêt !");

Soumettre une demande

Une fois le bouclier prêt, nous pouvons commencer à l'utiliser! Accrochez-vous, les choses amusantes commencent!

Demande simple

Pour commencer, nous devrons générer une requête pour interroger un serveur dans l'espoir d'obtenir une réponse. Je vous suggère de commencer par une chose simple, obtenir une page Web très basique, celle de

http://perdu.com

!

C'est là que notre variable de type "client"

EthernetClient

entre enfin en jeu. Ce dernier se chargera des interactions avec la page. Nous utiliserons sa méthode

relier ()

pour se connecter à un site, puis nous utiliserons sa méthode

println ()

pour construire notre demande et l'envoyer.

néant installer() 



erreur = client.connect (serveur, 80);

  si(erreur == 1) 

Serial.println ("Connexion OK, envoi en cours ...");


client.println ("GET / HTTP / 1.1");
client.println ("Hôte: Lost.com");
client.println ("Connexion: fermer");
client.println ();
 autre 

Serial.println ("La connexion a échoué");
    commutateur(faute) 
      cabane((-1):
Serial.println ("Temps libre");
        Pause;
      cabane((-2):
Serial.println ("Serveur non valide");
        Pause;
      cabane((-3):
Serial.println ("Tronqué");
        Pause;
      cabane((-4):
Serial.println ("Réponse invalide");
        Pause;

    tandis que((1);


Jetons un œil à ces quelques lignes.

Dans un premier temps, nous allons essayer de connecter notre client au serveur de "perd.com" sur son port 80 qui est le port par défaut du protocole HTTP:

client.connect ("lost.com", 80);

Ensuite, une fois que la connexion semble correcte, nous allons construire notre requête étape par étape.
Tout d'abord, nous expliquons que nous voulons faire un

Avoir

à la racine ("/") du site et le tout sous le protocole HTTP version 1.1.

client.println ("GET / HTTP / 1.1");

Ensuite, nous redéclarons le site qui fera (host, "host" en anglais) la réponse. Dans ce cas, nous restons sur Lost.com.

client.println ("Hôte: Lost.com");

Ensuite, le serveur est informé que la connexion sera fermée lorsque les données seront transférées.

client.println ("Connexion: fermer");

Enfin, pour éviter que nous venons de terminer l'écriture de notre en-tête (

entête

), nous envoyons une ligne blanche.

J'ai ensuite ajouté la gestion des erreurs pour savoir ce qui se passe en cas de problème.

Demande avec paramètre

Et si nous voulions transmettre des informations supplémentaires à la page? Et bien c'est simple, il suffit de modifier la requête GET en ajoutant les informations!
Par exemple, supposons que sur Lost.com, il existe une page de recherche "search.php" qui prend un paramètre "m" comme mot-clé de recherche. On aurait alors:

client.println ("GET /recherche.php?m=monmot HTTP / 1.1");

Il serait alors équivalent d'aller demander la page "perd.com/recherche.php?m=monmot", c'est-à-dire la page "recherche.php" avec comme argument de recherche "m" le mot "monmot" .

Lire une réponse

Lorsque la demande est envoyée (après le saut de ligne), le serveur nous répondra en nous envoyant la ressource demandée. Dans ce cas, ce sera la page d'accueil de Lost.com. Tu sais quoi? Nous ferons exactement comme avec un canal série. Nous commencerons par regarder si des données sont arrivées, et si c'est le cas, nous les lirons une par une et ensuite nous ferons ce que nous voulons (lignes de recomposition, chercher des choses dedans …)

Pour l'instant, publions tout sur le canal série!

Première étape, vérifiez que nous avons bien reçu quelque chose. Pour cela, comme avec Serial, nous utiliserons la méthode

disponible ()

qui renvoie le nombre de caractères disponibles pour la lecture.

Si des choses sont disponibles, nous les lisons un par un (comment?

lis ()

bien sûr !
: RÉ
) et les envoie au canal série en même temps:

réservoir carlu = 0;

si(client.available ()) 
carlu = client.read ();
Serial.print (carlu);

Enfin, lorsque tout aura été lu, nous vérifierons l'état de notre connexion et fermerons notre client si la connexion est complète.


si (! client.connected ()) 
Serial.println ();
Serial.println ("Se déconnecter!");

client.stop ();
  tandis que((1);

Dans l'ensemble, voici le code pour lire une réponse:

néant boucle()

  réservoir carlu = 0;
  
  si(client.available ()) 
carlu = client.read ();
Serial.print (carlu);


  
  si (! client.connected ()) 
Serial.println ();
Serial.println ("Se déconnecter!");

client.stop ();
    tandis que((1);


Avez-vous remarqué, plutôt que de lire tous les caractères avec un

tandis que

, nous n'en lirons qu'un à la fois dans

boucle ()

. C & # 39; est un choix de conception, avec un certain temps, cela fonctionnerait aussi!

Code complet

En résumé, voici le code complet pour lire la page "Lost.com"


#comprendre 
#comprendre 











octet mac[] =  0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E ;

Adresse IP ip((192,168,0,143);

Client EthernetClient;

réservoir serveur[] = "lost.com";

néant installer() 

Serial.begin (9600);

  réservoir erreur = 0;

erreur = Ethernet.begin (mac);

  si (erreur == 0) 
Serial.println ("Configuration avec IP fixe ...");


Ethernet.begin (mac, ip);

Serial.println ("Init ...");

retard (1000);
Serial.println ("Prêt !");


erreur = client.connect (serveur, 80);

  si(erreur == 1) 

Serial.println ("Connexion OK, envoi en cours ...");


client.println ("GET / HTTP / 1.1");
client.println ("Hôte: Lost.com");
client.println ("Connexion: fermer");
client.println ();
 autre 

Serial.println ("La connexion a échoué");
    commutateur(faute) 
      cabane((-1):
Serial.println ("Temps libre");
        Pause;
      cabane((-2):
Serial.println ("Serveur non valide");
        Pause;
      cabane((-3):
Serial.println ("Tronqué");
        Pause;
      cabane((-4):
Serial.println ("Réponse invalide");
        Pause;

    tandis que((1);



néant boucle()

  réservoir carlu = 0;
  
  si(client.available ()) 
carlu = client.read ();
Serial.print (carlu);


  
  si (! client.connected ()) 
Serial.println ();
Serial.println ("Se déconnecter!");

client.stop ();
    tandis que((1);


Et voici le résultat que vous devriez obtenir dans votre terminal série. Notez la présence de l'en-tête de la réponse que nous recevons.

HTTP / 1.1 200 OK
Date: jeu.26 mars 2015 16:14:15 GMT
Serveur: Apache
Dernière mise à jour: Tue, 02 Mar 2010 18:52:21 GMT
ETag: "cc-480d5dd98a340"
Accept-Ranges: octets
Longueur du contenu: 204
Varier: accepter-encodage
Connexion: fermer
Type de contenu: texte / html

Vous êtes perdu ?

Perdu sur Internet?

Ne vous inquiétez pas, nous vous aiderons

                * <----- vous êtes ici


Faire des demandes continues

Faire une demande au début du programme, c'est bien, mais il vaudrait mieux pouvoir le faire quand on veut. Faire évoluer notre programme ne sera pas si simple…

Pour commencer, nous ajouterons de nouvelles variables. Le premier sera utilisé pour se souvenir de la date (via

millis ()

) la dernière demande. Ce sera donc un

longue()

. La seconde sera une constante utilisée pour indiquer le temps minimum à s'écouler entre deux requêtes. Enfin, la dernière variable sera un booléen servant de

drapeau

pour indiquer l'état de la connexion (ouverte ou fermée) entre deux tours de boucle

boucle ()

.


longue lastRequest = 0;

const longue updateInterval = 10 000;

bool wasConnect = faux;

Ensuite, nous allons créer une fonction sobrement nommée

demande()

qui va construire et envoyer la demande. Rien de nouveau là-dedans, c'est le code que vous connaissez déjà.

néant demande() 
  
  réservoir erreur = client.connect (serveur, 80);

  si(erreur == 1) 

Serial.println ("Connexion OK, envoi en cours ...");


client.println ("GET / HTTP / 1.1");
client.println ("Hôte: Lost.com");
client.println ("Connexion: fermer");
client.println ();


lastRequest = millis ();
 autre 


client.stop ();

Serial.println ("La connexion a échoué");
    commutateur(faute) 
      cabane((-1):
Serial.println ("Temps libre");
        Pause;
      cabane((-2):
Serial.println ("Serveur non valide");
        Pause;
      cabane((-3):
Serial.println ("Tronqué");
        Pause;
      cabane((-4):
Serial.println ("Réponse invalide");
        Pause;



La seule différence ici est que nous fermons le client si la connexion a un problème et que nous enregistrons également l'heure à laquelle la demande a été effectuée.

Bien. Nous devons maintenant revoir notre boucle.

Le début ne change pas, nous récupérons / affichons les personnages s'ils sont disponibles.

Ensuite, nous avons eu l'étape de fermer le client si la connexion est fermée. Dans notre cas actuel, nous ne devons pas l'arrêter à tout moment, car sinon une connexion pourrait avoir lieu à nouveau sans que celle-ci soit terminée. Nous le fermerons donc UNIQUEMENT s'il était déjà clôturé à la toute fin du cycle précédent. Voici comment il peut être représenté:

néant boucle()

  
  

  
  
  
  si (wasConnect &&! client.connected ()) 
Serial.println ();
Serial.println ("Se déconnecter!");

client.stop ();







wasConnect = client.connected ();

Il ne nous reste plus qu'à relancer une demande si nos dix secondes se sont écoulées et que la connexion précédente a fini de fonctionner:



si(! client.connected () && ((millis () - lastRequete)> updateInterval)) 
demande();

Tout est clair? Voici le code complet pour vous aider à voir un peu mieux dans l'ensemble
;)
.

Le code complet


#comprendre 
#comprendre 











octet mac[] =  0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E ;

Adresse IP ip((192,168,0,143);

Client EthernetClient;

réservoir serveur[] = "lost.com";


réservoir carlu = 0;

longue lastRequest = 0;

const longue updateInterval = 10 000;

bool wasConnect = faux;

néant installer() 

Serial.begin (9600);

  réservoir erreur = 0;

erreur = Ethernet.begin (mac);

  si (erreur == 0) 
Serial.println ("Configuration avec IP fixe ...");


Ethernet.begin (mac, ip);

Serial.println ("Init ...");

retard (1000);
Serial.println ("Prêt !");


néant boucle()

  
  si(client.available ()) 
carlu = client.read ();
Serial.print (carlu);


  
  
  
  si (wasConnect &&! client.connected ()) 
Serial.println ();
Serial.println ("Se déconnecter!");

client.stop ();


  
  
  si(! client.connected () && ((millis () - lastRequete)> updateInterval)) 
demande();



wasConnect = client.connected ();


néant demande() 
  
  réservoir erreur = client.connect (serveur, 80);

  si(erreur == 1) 

Serial.println ("Connexion OK, envoi en cours ...");


client.println ("GET / HTTP / 1.1");
client.println ("Hôte: Lost.com");
client.println ("Connexion: fermer");
client.println ();


lastRequest = millis ();
 autre 


client.stop ();

Serial.println ("La connexion a échoué");
    commutateur(faute) 
      cabane((-1):
Serial.println ("Temps libre");
        Pause;
      cabane((-2):
Serial.println ("Serveur non valide");
        Pause;
      cabane((-3):
Serial.println ("Tronqué");
        Pause;
      cabane((-4):
Serial.println ("Réponse invalide");
        Pause;



L'intérêt d'un client

En lisant tout cela, vous pensez peut-être que l'utilisation du bouclier Ethernet en mode client est un peu inutile. C'est vrai, après tout, on ne peut même pas afficher les pages reçues!

Cependant, avec un peu d'imagination, on pourrait facilement voir plus que des utilisations pratiques!

Téléchargez une configuration

La première idée, par exemple, pourrait être de mettre des fichiers de paramètres à la disposition de l'Arduino. Imaginez par exemple que je fasse une application qui dépend des saisons. Mon application peut utiliser des moteurs et des capteurs pour effectuer certaines actions, mais les actions peuvent être différentes selon la période de l'année. Plutôt que de stocker 4 ensembles de paramètres dans l'Arduino, l'Arduino pourrait vérifier périodiquement en ligne (en interrogeant un petit script que nous aurions fait) pour savoir si quelque chose devait changer. Et voilà, configuration à distance!

Enregistrer des données en ligne

J'ai souvent lu sur des forums que les gens aimeraient pouvoir sauvegarder des choses dans une base de données. Bien sûr, l'Arduino seul ne peut pas le faire, la gestion d'une base de données est beaucoup trop compliquée pour cela. En revanche, il pourrait facilement interroger des pages en insérant des paramètres dans sa requête. La page qui reçoit alors la requête lira ce paramètre et se chargera de sauvegarder les informations.
Par exemple, on pourrait imaginer la demande

http://mapageweb.com/enregistr.php?&analog1=123&analog2=28&millis=123456

. Cette demande a deux paramètres,

analogique1

et

analogique2

qui pourrait être les valeurs des entrées analogiques et un "millis" final qui pourrait être la valeur de millis () d'Arduino. Notre page "save.php" serait alors enregistrée dans sa base de données!
Pour créer une telle requête, le code suivant devrait faire l'affaire:





client.print ("GET /save.php/?analog1=");
client.print (analogRead (A1));
client.print ("& analog2 =");
client.print (analogRead (A2));
client.print ("& millis =");
client.print (millis ());

client.println ("HTTP / 1.1");


client.println ("Hôte: mapageweb.com");
client.println ("Connexion: fermer");
client.println ();

Sûrement plein d'autres choses!

Il y a sûrement un tas d'autres idées auxquelles je n'ai pas pensé!

Exercice, lisez la disponibilité d'Eskimon.fr

Pour terminer ce chapitre je vous propose un petit exercice, lisez le temps de disponibilité (temps écoulé depuis le démarrage du système) sur mon blog, eskimon.fr.

Instructions

Pour cela, j'ai concocté une petite page rien que pour vous qui ne renvoie que ces informations, sans tout le bazar HTTP qui va avec une page classique. Vous obtiendrez alors simplement l'en-tête de la demande et la valeur brute du temps de disponibilité.

La page à interroger pour votre requête est:

http://eskimon.fr/public/arduino.php

Essayez de modifier votre code pour afficher ces informations
;)

Vous pouvez désormais naviguer sur Internet pour obtenir des informations. Bienvenue à l'IoT, l'Internet des objets!

Laisser un commentaire