Page 1 sur 1

Envoyer des données sur un serveur à partir de la Nspire

Message non luPosté: 07 Mar 2019, 16:02
de Noury
Nous avons vu il a quelques temps comment utiliser les broches RX et TX de la Nspire via un craddle. Voir ici
Nous allons voir aujourd'hui comment communiquer avec un serveur web.
Il ne s'agit pas de naviguer sur internet, mais de communiquer avec un serveur web pour envoyer des données. Il s'agira le plus souvent d'un serveur REST.
Ce que nous allons voir aujourd'hui n'a pas d'utilité directe. C'est plus un mode opératoire, un exemple pour envoyer des données à un serveur web.
Ça peut également servir pour passer un bon moment, et apprendre des choses.

Nous allons envoyer des données au serveur dweet.io. Il est en libre service, et ne nécessite aucune inscription.
C'est très pratique pour faire des tests.

La calculatrice sera connectée à un esp8266 qui est un micro contrôleur comme l'Atmel qui équipe les arduino. Il en existe plusieurs versions. Nous utiliserons la plus basique l'esp8266-01 qui coûte environ 2€. Des informations bonnes à lire concernant l'esp8266 sont disponibles ici. L'esp8266 peut fonctionner en client wifi, en serveur wifi (oui oui, serveur web), ou les deux.
Le composant sera fourni avec un firmware "AT". C'est à dire qui communique avec des commandes AT.
Il est possible de le faire à partir d'une console série. Je l'ai fait pour ma part à partir de la console série de l'IDE Arduino.
Remarque: Les firmwares fournis peuvent fonctionner par défaut en 9600 bauds ou en 115200 bauds.
Il faut éventuellement le reconfigurer, car la Nspire ne fonctionne qu'en 115200.

Voici ce qui sera nécessaire:
1 - installer le sdk Ndless. Il sera utile pour développer en C ou en assembleur.
Le mode d'emploi est disponible ici
Je l'ai personnellement installé sur Mac et sur Linux. Mais c'est possible sous Windows. Il faut alors Cygwin.
L'installation est simple, mais longue. Il m'a fallu une demi journée. Ça dépend des performances de l'ordi.
2 - Créer un répertoire .nspire sous la home directory
3 - y copier les répertoires /rep_d_installation/Ndless/ndless-sdk/lib et /rep_d_installation/Ndless/ndless-sdk/include
4 - Ajouter au PATH les répertoires /rep_d_installation/Ndless/ndless-sdk/toolchain/install/bin et /rep_d_installation/Ndless/ndless-sdk/bin. Le faire de manière pérenne dans votre .profile (ou autre fichier de votre choix)
5 - enlever la ligne "uart_putchar(tmp);" du fichier /rep_d_installation/Ndless/ndless-sdk/thirdparty/nspire-io/arch-nspire/nspire-uart.c
Ceci ne sera plus nécessaire quand la fonction sera adaptée. Mais c'est indispensable pour le moment.

Nous allons maintenant créer un répertoire de travail pour y placer notre code
Placons-y nos fichiers suivants:

- esp8266_avec_dweet.io.c
- esp8266_avec_dweet.io.h
- utils.c

Construisons le makefile à l'aide de la commande: nspire-tools new esp8266_avec_dweet.io
Il faut ensuite Modifier le Makefile. Remplacer la ligne "LDFLAGS =" par "LDFLAGS = -Wl,--nspireio,--gc-sections" car nous allons utiliser la bibliothèque nspireio

Compilons: make

C'est prêt le fichier .tns doit être envoyé sur la TI-Nspire. Ndless doit avoir été installé sur la calculatrice.
Il suffit maintenant de mettre la calculatrice sur le craddle, de relier la calculatrice à l'esp8266, de mettre sur ON l'interrupteur du craddle, et enfin d'exécuter le programme pour observer ce qui se passe.
On pourra vérifier sur le site dwwet.io que tout a fonctionné.

Mais voyons d'abord les détails:

le fichier utils.c

Code: Tout sélectionner
#include <nspireio/nspireio.h>

int uart_getsn_AT(char* str, int num) {
    int i = 0;
    int max = num-1;
    for(int j = 1; j <= 10000000; j++) {
        while(uart_ready()) {
            if(i == max) {
                str[i] = 0;
                return 3;
            }
            char c = uart_getchar();
            str[i] = c;
            if(c == '\b') { i -= 2; }
            else {
               if(strncmp(str+i-7, "\r\n\r\nOK\r\n",8) == 0) {
                    str[i+1] =0;
                    return 1; // OK
                }
                else if(strncmp(str+i-10, "\r\n\r\nERROR\r\n",11) == 0) {
                    str[i+1] =0;
                    return 0; // ERROR
                }
            }
            i++;
        }
    }
    str[i] = 0;
    return 3; // UNKNOWN
}

int send_AT_command(char *cmd, int lg_buffer, char *buffer) {
  int ret;
  nio_printf("Sending %s\n", cmd);
  uart_puts(cmd);
  ret = uart_getsn_AT(buffer,lg_buffer);
  nio_printf("Response from esp8266 is : %s\n",buffer);
  return ret;
}


La fonction uart_getsn_AT est une fonction adaptée de la fonction uart_getsn de la bibliothèque nspirio.
Son rôle est de lire les données issues de l'esp8266
Il a été nécessaire de la réécrire car l'originale n'était pas adaptée à la communication à l'aide de commandes AT. Il n'était pas non plus possible de faire une surcouche.
Je vais donc proposer à l'auteur de la bibliothèque d'ajouter cette nouvelle fonction.
Cette fonction lit le buffer de réception jusqu'à la rencontre des chaines "<CR><LF><CR><LF>OK<CR><LF>" ou "<CR><LF><CR><LF>ERROR<CR><LF>", qui sont renvoyées par tout dispositif AT.
Mais d'autres cas peuvent se produire, un reset par exemple. C'est ce qui explique la boucle "for "de sécurité. Les réponses seront:
1 - tout est OK
2 - erreur AT. Ce n'est pas forcément une erreur d'exécution de notre programme
3 - autre cas d'anomalie

Remarque importante:

Surtout ne pas ajouter d'instructions à cette fonction, pour débugger par exemple. En particulier des instructions d'E/S.
C'est un traitement temps réel. Le risque est de perdre des caractères en entrée.
C'est du vécu !

La fonction send_AT_command envoit la commande à l'esp8266.
Si vous trouvez qu'il y a trop d'affichages, et qu'un debug n'est pas nécessaire, il est possible de commenter la ligne "nio_printf("Sending %s\n", cmd);"

Le fichier esp8266_avec_dweet.io.c

Code: Tout sélectionner
#include <nspireio/nspireio.h>

#include "esp8266_avec_dweet.io.h"

int main()
{
  char input[5000] = {0};
  int ret;
  char cmd[300];

  /* Commande basique de test d'une commande AT */
  ret = send_AT_command("AT\r\n", 100, input);

  /* Commande AT un peu plus élaborée : demande de la version du firmware de l'esp8266*/
  ret = send_AT_command("AT+GMR\r\n", 100, input);

  /* Demande de la liste des points d'accès disponibles */
  ret = send_AT_command("AT+CWLAP\r\n", 5000, input);

  /* Consultation du mode configuré actuellement: station, serveur, les deux */
  ret = send_AT_command("AT+CWMODE?\r\n", 100, input);

  /* Configuration du mode client */
  ret = send_AT_command("AT+CWMODE=1\r\n", 100, input);

  /* Connexion au point d'accès */
  strcpy(cmd, "AT+CWJAP=\"ssid du point d'accès à utiliser\",\"mot de passe\"\r\n");
  send_AT_command(cmd, 500, input);

  /* Demande de l'adresse IP attribuée (pour consultation) */
  ret = send_AT_command("AT+CIFSR=1\r\n", 100, input);

  /* Configuration d'un canal unique de communication, un seul suffit */
  ret = send_AT_command("AT+CIPMUX=0\r\n", 100, input);

  /*
   ** Nous allons maintenant envoyer la date et 'heure au serveur dweet.io
  */

  /* On récupère la date et l'heure au bon format */
  time_t t = time(NULL);
  struct tm tm = *localtime(&t);
  char dt[11];
  char hr[9];
  sprintf(dt, "%02d-%02d-%d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
  sprintf(hr, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);

  /* On prépare les données "utiles" de la commande POST */
  char data[100];
  char lgr_data[4];
  strcpy(data, "{\"date\":\"");
  strcat(data, dt);
  strcat(data, "\",\"heure\":\"");
  strcat(data, hr);
  strcat(data, "\"}");
  sprintf(lgr_data, "%lu", strlen(data));

  /* On construit la commande POST */
  char post[500];
  char lgr_post[4];
  strcpy(post, "POST /dweet/for/identifiant HTTP/1.1\r\nHost: dweet.io\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: ");
  strcat(post, lgr_data);
  strcat(post, "\r\n\r\n");
  strcat(post, data);
  strcat(post, "\r\n\r\n");

  /* Connexion au serveur web */
  ret = send_AT_command("AT+CIPSTART=\"TCP\",\"dweet.io\",80\r\n", 100, input);

  /* Construction de la commande AT qui indique la longueur */
  sprintf(lgr_post, "%lu", strlen(post));
  strcpy(cmd, "AT+CIPSEND=");
  strcat(cmd, lgr_post);
  strcat(cmd, "\r\n");

  /* On y ajoute le POST */
  strcat(cmd, post);

  /* On envoit la commande complète */
  ret = send_AT_command(cmd, 5000, input);

  puts("Bye!");
  wait_key_pressed();
  return 0;
}


Plusieurs commandes sont exécutées dans ce programme:
Il n'est pas obligatoire de les exécuter toutes. En particuliers les premières peuvent exécutées une à une, pour vérifier que tout va bien.
- AT qui est une commande simple qui fait répondre "OK" par l'esp8266 si tout se passe bien
- AT+GMR qui demande à l'esp8266 la version du firmware
- AT+CWLAP qui affiche la liste des points d'accès
- AT+CWMODE? qui demande le mode de fonctionnement actuel (1: station, 2: serveur, 3: les deux)
Les commandes qui suivent seront nécessaires pour notre test
- AT+CWMODE=1 pour forcer le mode station
- AT+CWJAP="ssid du point d'accès à utiliser","mot de passe" (guillemets obligatoires)
Cette commande permet de se connecter au point d'accès choisi.
- AT+CIFSR=1 permet de consulter l'adresse ip qui nous a été attribuée. Cette commande n'est pas obligatoire pour notre test.
- AT+CIPMUX=0 pour n'utiliser qu'un canal de communication. La plupart des exemples sur internet en utilisent plusieurs, mais c'est inutile.

Nous construisons ensuite le message à envoyer au serveur
Nous allons envoyer deux variables nommées "date" et "heure", qui contiendront la date et l'heure au moment de l'exécution.
Les commandes AT+CIPSTART="TCP","dweet.io",80
et "AT+CIPSEND=" envoient les données au serveur. AT+CIPSEND sera dans notre cas suivi d'une commande "POST". C'est intéressant, car sur le web on ne trouve que des commandes "GET".

Donc, penser à modifier dans le source:
- le ssid
- le mot de passe
- l'identifiant dweet.io (c'est une chaine libre. Elle permettra de consulter le résultat sur le site)

Le fichier esp8266_avec_dweet.io.h:

Code: Tout sélectionner
char* uart_getscrlf(char* str, int num);
int uart_getsn_AT(char* str, int num);
int send_AT_command(char *cmd, int lg_buffer, char *buffer);

Ce sont nos définitions de fonctions.

Les connexions

Il faut juste relier:
- la masse de la Nspire à la masse de l'esp8266
- le RX de la Nspire au TX de l'esp8266
- le TX de la Nspire au RX de l'esp8266

Pour vérifier le résultat sur le serveur, ouvrir un navigateur, et taper l'url: http://dweet.io/follow/identifiant
Remplacer "identifiant" par celui utilisé dans votre programme.

Voilà, j'espère que ça vous poussera à faire des choses plus utiles, et que vous passerez un bon moment.

edit: Voici le schéma de câblage

Image

Re: Envoyer des données sur un serveur à partir de la Nspire

Message non luPosté: 16 Mar 2019, 19:37
de Noury
Je pense que certaines personnes qui auraient voulu essayer ce montage et le programme associé, ont renoncé car elles n'ont pas l'environnement de développement adéquat.
J'ai donc décidé de packager davantage ce kit d'essai.
Un zip attaché à ce post contient:
- les sources modifiés pour une interaction avec l'utilisateur
- le tns obtenu après compilation (ce qui devrait simplifier considérablement les tests)
- le schéma de câblage

Concernant le câblage, comme l'esp8266 consomme très peu, il sera alimenté par la TI-Nspire.
Le voici:

Image

Voici une photo du kit en cours d'exécution:
Image

On peut trouver l'esp8266-01 (modèle 01, pas un autre), pour 1,50€ sur ebay.

Le programme n'est pas "blindé" contre toutes les anomalies possibles, mais il est conçu pour éviter au maximum les insupportables "reset". Au maximum, mais pas complètement.
Pour ça, il y a une boucle de temporisation. Si le programme n'arrive pas à communiquer correctement, il faut patienter quelques dizaines de secondes. En général, ça suffit pour quitter l'application.

Le fonctionnement du programme est globalement le suivant:
- envoi d'une commande "AT" de test pour vérifier la communication avec l'esp8266
- arrêt si problème
- récupération des points d'accès disponibles et affichage de ceux-ci
(à noter que seuls les points d'accès à 2,4GHz fonctionnent avec cet ESP. Les 5GHz ne sont pas reconnus)
- demande de choisir l'un d'entre-eux
- demande du mot de passe
- tentative de connexion
- demande de l'identifiant dweet.io. C'est une chaine de caractères de votre choix.
- envoi de 2 variables et de leurs valeur au serveur dweet.io
Ce sont les variables "date" et "heure". Les valeurs sont la date et l'heure actuelle.

Il faut aller ensuite à l'aide d'un navigateur sur l'url http://dweet.io/follow/XXXX (XXXX étant l'identifiant choisi plus tôt)
On peut y voir le résultat du traitement.

Il faut considérer ce kit comme un kit d'initiation, c'est pour vulgariser ce genre de choses.

S'il y a des questions ou des remarques, ne pas hésiter.

Re: Envoyer des données sur un serveur à partir de la Nspire

Message non luPosté: 17 Mar 2019, 15:08
de Adriweb
Superbe !

Re: Envoyer des données sur un serveur à partir de la Nspire

Message non luPosté: 18 Mar 2019, 09:27
de Noury
Merci @Adriweb

Re: Envoyer des données sur un serveur à partir de la Nspire

Message non luPosté: 18 Mar 2019, 12:50
de Wistaro
Excellent.
J'ai bien envie d'essayer :p

Je ferai ça quand j'aurai un peu de temps.

Re: Envoyer des données sur un serveur à partir de la Nspire

Message non luPosté: 04 Fév 2021, 01:08
de Aubain
Vraiment merci ! Tes explications sont parfaites et limpides.

Re: Envoyer des données sur un serveur à partir de la Nspire

Message non luPosté: 05 Fév 2021, 23:40
de Aubain
Je rencontre un problème dans mon montage high-tech. La borne GND est-elle commune à plusieurs bonnes positives ?