Passer une valeur String en variable hexadecimale

Bonjour à tous,

J'ai un projet d'allumage d'un ruban leds NéoPixel WS2812B collé derrière ma télé via mon téléphone.
Le ruban est branché à un ESP32 ou le Vcc passe par un relais.
Le sélecteur de couleurs et le bouton d'allumage sont déclenché par un serveur NodeRed dashboard 2 via MQTT et envoyé à mon ESP32.

Lorsque je clique sur le bouton allumage des leds, le relais s'active bien.
Lorsque je sélectionne une couleur, le moniteur série de l'ESP me renvoi une valeur de type String((char*)payload); représentant une valeur hexadécimale de la couleur.

Capture1

Voici la fonction qui réceptionne la valeur du bon topic :

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    
  }
  payload[length]='\0';
  String cons = String((char*)payload);
  consigne = cons;
  Serial.println();

// --------------------  Exécution des souscription au topic MQTT  ----------------------------------

if(topic[7] == 'a') {                                                                                  
    payload[length]='\0';                                 
    callbackAllumageLedsTeleviseur = String((char*)payload);    
    Serial.println();
} else if (topic[7] == 'o') {
   payload[length]='\0';
   callbackChoixCouleurs = String((char*)payload);
   Serial.println();
 }
}

Et voici l'intéraction dans la void loop() :

// -------------------------  Lecture des conditions de déclenchement des relais pilotés MQTT + lecture couleurs  ----------------------------------

if(callbackAllumageLedsTeleviseur == "true") { 
  
delay(500);
  
  digitalWrite(relaisAllumageLeds, HIGH);
  
} else {
  digitalWrite(relaisAllumageLeds, LOW);
 }

callbackChoixCouleurs = couleurLeds; // couleurLeds est édité au début du programme en unsigned long

 if(callbackAllumageLedsTeleviseur == "true"){
  for( int i=0; i<=LED_COUNT; i++ ){
    rubanLedsTele.Color(i, couleurLeds);
    rubanLedsTele.show();
    Serial.println(couleurLeds);
  }
 }

J'aimerais pouvoir récupérer la valeur String et la transformer en valeur intégrable dans une variable rubanLedsTele.Color(i, couleurLeds); qui peut changer dès que je sélectionne une autre couleur.
Faut il passer par strcmp() ? Je n'ai encore jamais été confronté à ce genre de problème.

Merci par avance pour votre aide.
Ludo

Les objets Strings possèdent des méthodes permettant de faire des recherches dans la chaîne de caractères et d'en extraire des nombres

https://docs.arduino.cc/language-reference/en/variables/data-types/stringObject/

indexOf() pour chercher une sous-chaine
charAt() pour chercher un caractère
Et des fonctions de conversion de texte vers des nombres de différents types
toDouble()
toInt()
toFloat()

Merci pour les liens, je vais étudier ça :wink:

J'ai réussi a obtenir chaque caractères avec la fonction suivante :

void rechercheDesCaracteres() { 
char caractereUn = callbackChoixCouleurs.charAt(0);
char caractereDeux = callbackChoixCouleurs.charAt(1);
char caractereTrois = callbackChoixCouleurs.charAt(2);
char caractereQuatre = callbackChoixCouleurs.charAt(3);
char caractereCinq = callbackChoixCouleurs.charAt(4);
char caractereSix = callbackChoixCouleurs.charAt(5);
char caractereSept = callbackChoixCouleurs.charAt(6);
char caractereHuit = callbackChoixCouleurs.charAt(7);
char caractereNeuf = callbackChoixCouleurs.charAt(8);


Serial.println("1: " + String(caractereUn) +"\t" + "2: " + String(caractereDeux) + "\t" + "3: " + String(caractereTrois) + "\t" + "4: " + String(caractereQuatre) + "\t" + "5: " + String(caractereCinq) + "\t" + "6: " + String(caractereSix) + "\t" + "7: " + String(caractereSept) + "\t" + "8: " + String(caractereHuit) +"\t" + "9: " + String(caractereNeuf));
}

Voici ce que j'obtiens dans le débug :

Capture1

Par contre, je ne vois pas comment intégrer chaque caractère dans une variable.
J'ai testé avec concat() mais le type int de ma variable n'est pas bon.

Une idée ?

En fait, je ne vois pas clairement la finalité.
Tu veux extraire chaque caractère séparément pour en récupérer sa valeur ou bien tu veux un nombre de 2, 3, 4, .. digits ??

Je viens de simplifier le payload de node red qui arrive sur l'ESP32 car la bibliothèque Adafruit ne prend en compte que les valeurs RGBA, donc voici ce que je récupère en payload au final :

Mon objectif est de récupérer la valeur de chaque couleur RGBA pour qu'elles s'intègrent automatiquement dans la fonction rubanLedsTele.Color(r, g, b), a);
Pour le coup, je pense qu'il faut repérer les trois caractères de chaque couleur afin de créer une variable par couleur et intégrer ces variables dans la fonction ci-dessus.

Est-ce que tu reçois toujours 3 caractères par couleur?
Si la valeur est, par exemple, 10 tu recevras 10 ou 010?

Chaque couleur va de 0 à 255.
Le Payload arrive sous la forme de {1, 34, 200} et non pas { 001, 034, 200}

Donc, maintenant, le message reçu n'est plus de cette forme: {"r":180,"g":124,"b":103,"a":1} comme indiqué au post précédent?
Faudrait voir à figer le protocole une bonne fois pour toute.

Donc avec {1, 34, 200} tu devrais faire quelque chose comme ceci:

  • tu sais que la première valeur commence à l'index 1 donc tu peux faire
    int valeur1 = message.toInt(1) qui extraira le premier nombre. La méthode toInt() arrête automatiquement la conversion au premier caractère non numérique.
  • pour la seconde valeur, tu sais qu'elle se trouve après une virgule donc tu fais
    index = message.indexOf(",") pour trouver la position de la première virgule.
    int valeur2 = message.toInt(index+1) pour extraire le nombre qui commence après la virgule
  • pour la troisième valeur, il faut trouver la seconde virgule
    index = message.indexOf(",", index+1) on utilise index pour commencer la recherche après la première virgule
    int valeur3 = message.toInt(index+1) pour extraire le dernier nombre

Excuse moi, c'était pour l’illustration.
Voici ce matin ce que j'ai pu faire :

char caractereRUn = callbackChoixCouleurs.charAt(4);
char caractereRDeux = callbackChoixCouleurs.charAt(5);
char caractereRTrois = callbackChoixCouleurs.charAt(6);

char caractereGUn = callbackChoixCouleurs.charAt(12);
char caractereGDeux = callbackChoixCouleurs.charAt(13);
char caractereGTrois = callbackChoixCouleurs.charAt(14);

char caractereBUn = callbackChoixCouleurs.charAt(20);
char caractereBDeux = callbackChoixCouleurs.charAt(21);
char caractereBTrois = callbackChoixCouleurs.charAt(22);

Serial.println("R1: " + String(caractereRUn) +"\t" + "R2: " + String(caractereRDeux) + "\t" + "R3: " + String(caractereRTrois) + "\t" + "G1: " + String(caractereGUn) + "\t" + "G2: " + String(caractereGDeux) + "\t" + "G3: " + String(caractereGTrois) + "\t" + "B1: " + String(caractereBUn) + "\t" + "B2: " + String(caractereBDeux) +"\t" + "B3: " + String(caractereBTrois));

Voici le retour du moniteur série avec une valeur avec deux valeurs différentes :

Je m'aperçois que l'index change selon les dizaines et les centaines. Je vais revoir ça ce soir. Merci

C'est pour cela que je proposais d'utiliser .indexOf() pour faire chercher le séparateur.

Donc, au final c'est cela que tu reçois
{"r":180,"g":124,"b":103,"a":1}
Si c'est le cas, il suffit de faire chercher la position des sous-chaines "r":, "g": et "b": en utilisant .indexOf()
Et ensuite d'extraire la valeur avec .toInt(index+4) +4 pour pointer juste derrière les :

J'ai modifier la recherche du coup mais j'ai un problème d'écriture, ça ne téléverse pas avec un problème dans la fonction toInt()

Capture1

Voici le code :

int premiereChaineCouleurR = callbackChoixCouleurs.indexOf(":");
int couleurR = callbackChoixCouleurs.toInt(premiereChaineCouleurR + 1);

int secondeChaineCouleurG = callbackChoixCouleurs.indexOf(":", premiereChaineCouleurR + 1);
int couleurG = callbackChoixCouleurs.toInt(secondeChaineCouleurG + 1);

int troisiemeChaineCouleurB = callbackChoixCouleurs.indexOf(":", secondeChaineCouleurG + 1);
int couleurB = callbackChoixCouleurs.toInt(troisiemeChaineCouleurB + 1);

Serial.print("Position chaine 1 / valeur chaine 1 : ");
Serial.println("R : " + String(premiereChaineCouleurR) +"\t" + "R : " + String(couleurR));

Serial.print("Position chaine 2 / valeur chaine 2 : ");
Serial.println("G : " + String(premiereChaineCouleurG) +"\t" + "G : " + String(couleurG));

Serial.print("Position chaine 3 / valeur chaine 3 : ");
Serial.println("B : " + String(premiereChaineCouleurB) +"\t" + "B : " + String(couleurB));

Les lignes :
int premiereChaineCouleurR = callbackChoixCouleurs.indexOf(":");

int secondeChaineCouleurG = callbackChoixCouleurs.indexOf(":", premiereChaineCouleurR + 1);
int troisiemeChaineCouleurB = callbackChoixCouleurs.indexOf(":", secondeChaineCouleurG + 1);
La position des caractères ":" se fait bien car le débug me ramène le bon positionnement.

Une idée ?

Je me suis planté, il n'y a pas d'argument à la méthode toInt().
Je regarde ça.

String callbackChoixCouleurs= "{\"r\":180,\"g\":124,\"b\":103,\"a\":1}";

int r,g,b;

void setup() {

  Serial.begin(115200);
  Serial.print("callbackChoixCouleurs =");Serial.println(callbackChoixCouleurs);
  unsigned int indexDebut = callbackChoixCouleurs.indexOf(":");
  unsigned int indexFin = callbackChoixCouleurs.indexOf(",", indexDebut + 1);
  String valeur_s = callbackChoixCouleurs.substring(indexDebut+1, indexFin);
  r = valeur_s.toInt();

  indexDebut = callbackChoixCouleurs.indexOf(":", indexFin);
  indexFin = callbackChoixCouleurs.indexOf(",", indexDebut + 1);
  valeur_s = callbackChoixCouleurs.substring(indexDebut+1, indexFin);
  g = valeur_s.toInt();

  indexDebut = callbackChoixCouleurs.indexOf(":", indexFin);
  indexFin = callbackChoixCouleurs.indexOf(",", indexDebut + 1);
  valeur_s = callbackChoixCouleurs.substring(indexDebut+1, indexFin);
  b = valeur_s.toInt();

  Serial.print("r ="); Serial.println(r);
  Serial.print("g ="); Serial.println(g);
  Serial.print("b ="); Serial.println(b);
}

donne

callbackChoixCouleurs ={"r":180,"g":124,"b":103,"a":1}
r =180
g =124
b =103

Une variante peut-être un peu plus élégante

String callbackChoixCouleurs= "{\"r\":180,\"g\":124,\"b\":103,\"a\":1}";

int r,g,b;

void setup() {

  Serial.begin(115200);
  Serial.print("callbackChoixCouleurs =");Serial.println(callbackChoixCouleurs);
  unsigned int indexDebut = 0;
  unsigned int indexFin = 0;

  for(int i=0; i<3; i++){
    indexDebut = callbackChoixCouleurs.indexOf(":", indexFin);
    indexFin = callbackChoixCouleurs.indexOf(",", indexDebut + 1);
    String valeur_s = callbackChoixCouleurs.substring(indexDebut+1, indexFin);

    switch (callbackChoixCouleurs.charAt(indexDebut - 2)){
      case 'r' :   r = valeur_s.toInt();
        break;
      case 'g' :   g = valeur_s.toInt();
        break;
      case 'b' :   b = valeur_s.toInt();
        break;
      default:
        break;
    }
  }

  Serial.print("r ="); Serial.println(r);
  Serial.print("g ="); Serial.println(g);
  Serial.print("b ="); Serial.println(b);
}

Résultat identique

callbackChoixCouleurs ={"r":180,"g":124,"b":103,"a":1}
r =180
g =124
b =103

Merci pour ces exemples, je vais étudier ça et je te redirais, à première vu, le retour des couleurs se passe bien mais je veux décortiquer la méthode !
Encore merci