[Aide] Ecouter un port série à travers un Node.js

Bonjour,

J'essaie de me bricoler des fonctions pour commander un Arduino à partir d'une fiction intéractive de style Twine. Twine, en gros, cela vous fabrique un .html du type "livre dont vous êtes le héros", sans que vous ayez à savoir programmer du .html ... Twine supporte plusieurs formats d'histoire, j'utilisais d'abord Harlowe mais il m'a vite semblé que SugarCube était meilleur pour implémenter des javascripts et c'est ce dont on a besoin.

Donc, "en gros", j'ai un site qui utilise des javascripts pour envoyer des instructions à une Arduino UNO, à travers le port COM4 et à travers un Server Node.

J'ai réalisé une première partie qui réussit à envoyer des variables de type "char". Là, je sens que je vais devoir copier du code (celui qui marche d'abord)...

void loop() {
  if (Serial.available() > 0) {  
    char command = Serial.read(); 
    if (command == 'H') {  
      digitalWrite(7, HIGH);} 
    else if (command == 'L') { 
      digitalWrite(7, LOW); 
    }
  }}

De l'autre côté, j'ai mon javascript dans Twine qui utilise ce code là :

<<script>>
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "http://localhost:3000/H");
  xhr.send();
<</script>>

Là, quand j'appelle ce script, le bousin envoie "http://localhost:3000/H" et le server Node envoie un H docilement sur le port COM de mon Arduino, qui le réceptionne et qui m'allume ma LED. Cela marche, c'est parfait, je suis content ...
Maintenant, je veux passer à la vitesse supérieure et envoyer des variables plus complexes à mon Arduino, par exemple en envoyant du texte à afficher sur un écran LED à partir d'un PROMPT ...

Naturellement, j'ai essayé dans un premier temps à updater mon code en essayant d'utiliser des "strings". Cela n'a pas marché et j'ai lu le tuto sur l'écoute des ports séries de J-M-L que j'ai trouvé via une réponse à quelqu'un qui a fait quelque chose comme moi ...

Donc ça donnait quelque chose comme ça :

void loop() {
  if (Serial.available() > 0) { 
    String command = Serial.readStringUntil('\n');
    if (command == 'HelloWorld') {  
     digitalWrite(7, HIGH);  
    } else if (command == 'Ciao') { 
      digitalWrite(7, LOW);  
    }
  }}

Et avec un script derrière qui ressemblait à ça :

<<script>>
  var xhr = new XMLHttpRequest();
  xhr.open("GET",  "http://localhost:3000/HelloWorld\n");
  xhr.send();
<</script>>

avec ou sans \n, avec ou sans #, avec ou sans \0 ...
La requête part bien. J'ai essayé de l'envoyer directement ... ça part, ça ne lit pas à l'Arduino.

BON, j'ai lu le tuto, et j'ai remis à jour mon code en suivant les instructions de JML. Et ça marchait, du moins à travers le Serial Monitor du Arduino IDE. Quand je tape "HelloWorld" sur le Monitor IDE, la Arduino UNO me répond bien les lettres une à une et le mot au final.

Mais quand j'essaie le même code non pas à travers le COM série de l'Arduino mais à travers le Node.js, je n'ai rien. Et je suis bien embêté parce que comme je ne peux pas avoir ouvert en même l'Arduino Ide et le NodeJS (cela me crée un conflit de port COM), je n'arrive pas à savoir ce qui passe, ce qui ne se passe pas ...
Je suspecte la donnée d'arriver sous un format que je ne comprends et que "du coup", l'Arduino est perdu. Mais en vrai, je suis un peu à court d'idées. Pourquoi ça marche quand j'envoie un H et pas un HelloWorld ...?

Après, il est possible que ce qui soit défectueux, c'est le code pour interpréter le message long.
En effet, la méthode du (tutoriel de jml) produit un c-string. J'ai essayé "plein" d'instructions pour lire ce C-string avec un seul caractère, H (envoyer H en char, ça marchait ... donc pourquoi pas essayer d'envoyer H en C-string ou même en string ...). Cela a donné ce code là hier soir, mais c'est tellement pourri que j'ai un peu honte ...

void loop() {
 if (! ecouter()) {
   if (message == 'H\0') { 
     digitalWrite(7, HIGH);} 
   else if (message == 'L\0') { 
     digitalWrite(7, LOW);}  
 }
 if (! ecouter()) {
   if (message == 'H') {  
     digitalWrite(7, HIGH);}  
   else if (message == 'L') {  
     digitalWrite(7, LOW);}  
 }
if (! ecouter()) {
   if (message == 'H#') {  
     digitalWrite(7, HIGH);}  
   else if (message == 'L#') {  
     digitalWrite(7, LOW);}  
 }
}

Je soupçonne que le server node.js ne fait pas les appels de pied qui trigger le "écouter" ce qui fait échouer les méthodes "prescrites", mais j'en sais rien.
J'avoue que je commençais à accuser la fatigue hier soir. C'est sans doute quelque chose sur lequel vous devriez pouvoir m'éclairer en cinq secondes... Dans tous les cas, je vous remercie du temps passé à me lire.

pour comparer des cString on utilise la fonction strcmp() qui répond 0 si les 2 chaines sont identiques - comme montré dans un des exemples du tuto

dans votre cas, vous pourriez faire par exemple

if (! ecouter()) {
  // on a reçu un message
  if (strcmp(message, "H") == 0) {
    digitalWrite(7, HIGH);
  }
  else if (strcmp(message, "L") == 0 {
  digitalWrite(7, LOW);
  }
  else if (strcmp(message, "H#") == 0 {
  digitalWrite(7, HIGH);
  }
  else if ...
}

une cString se note avec des guillemets, par entre apostrophe (c'est réservé pour représenter un caractère)

attention à ne pas appeler écouter plus que de nécessaire car une fois le message reçu vous démarrez une nouvelle écoute, donc il faut mettre tous les tests dans le if qui teste la réception

1 Like

C'est donc du coté du code sur le serveur node.js qu'il faut regarder.
Comme tu ne le donne pas, c'est difficile de savoir si tu envois bien toutes la chaines données dans la requêtes HTTP ou seulement le premier, puisque ce test à fonctionné.

Je vous remercie de vos réponses.

Je n'avais en effet pas vu dans le tutoriel que l'appel pour vérifier le conditionnel d'une c-string n'était pas le même que pour un caractère. C'était la dernière chose que j'avais regardée et en effet, j'étais un peu fatigué (en témoigne mon codage dégueulasse de fin...).

Si malgré tout, je n'y arrive, il faudra en effet que j'aille voir du côté du serveur ... mais là, on passe vraiment dans un domaine qui me dépasse beaucoup. J'espère donc que la première solution est la bonne.

Je reteste et je reviens vers vous.

Bien.

Donc j'ai du un peu batailler, principalement parce que j'avais branché ma LED sur la mauvaise sortie (... ne riez pas...). Mais cela a marché.
J'ai fait des tests avec le Monitor série jusqu'à ce que j'obtienne ce que je veux. Il fallait que j'entre manuellement le symbole de fin dans mon instruction pour que ça marche, mais une fois cela remarqué, ça marchait et donc j'étais content.

Je suis ensuite passé à mes instructions à travers le Server Node ... Là, ça ne marchait plus. J'étais donc à deux doigts de me désespérer. J'ai essayé d'envoyer la consigne manuellement et j'ai remarqué que le symbole de fin ne passait pas. Plutôt, qu'il était mangé dans le transfert et qu'en quelque sorte, il me fallait deux symboles de fin différents.

C'est donc ce que j'ai fait.

J'ai corrigé l'annonce de marqueur de fin pour le faire devenir un $.

const char marqueurDeFin = '$';

et mon javascript est devenu :

<<script>>
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "http://localhost:3000/Hello$");
  xhr.send();
<</script>>

Le dollar n'est pas consommé dans le transfert à travers le serveur, il arrive à mon Arduino et arrête bien l'écoute. La vérification du message avec le StringCompare se fait sans $ et ça marche.

Maintenant, comme le but était d'alimenter quelque chose de mieux qu'une loupiotte, je vais voir si je réussis à écrire ce que je veux sur un écran LED. Mais je crois que ce problème est désormais fini. (Je laisse encore un peu ouvert au cas où...)

Merci encore à tous :smiley: !

c'était quoi avant ? un passage à la ligne ?

Un # je crois ...

c'est l'explication alors.

Lorsque vous faites une requête à l'URL par exemple http://localhost:3000/Hello#coucou, le serveur ne reçoit que la partie avant le #, c'est-à-dire http://localhost:3000/Hello.

Le fragment (dans ce cas, #coucou) est géré uniquement par le navigateur. Il est utilisé pour naviguer vers une section spécifique de la page après que celle-ci ait été chargée. Le serveur ne reçoit pas cette information, car le fragment n'est pas inclus dans la requête HTTP envoyée au serveur.

c'est pour cela que lorsque vous faisiez http://localhost:3000/Hello# le serveur ne voyait que http://localhost:3000/Hello

1 Like

Oui, j'avais réussi à superpasser cette difficulté. J'ai réussi à finaliser mon objectif du jour : réussir à faire afficher sur un écran LED les entrées d'un prompt d'un site Internet. J'ai encore quelques petites babioles esthétiques à régler (effacer l'écran LED avant de réécrire dessus, etc etc), mais cela devrait être dans mes compétences.

Je vous remercie encore en tout cas et je ne sais pas trop quel message choisir en solution. Sans doute le premier où l'on me tirait sur les oreilles pour avoir analysé le tutoriel jusqu'au bout.

:wink:

vous pouvez marquer votre post 5 puisque vous avez résolu vous même le souci

1 Like

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