Intégrer un float dans une chaine de caractère (requête HTTP): HEEEELP !

Bonjour à toutes et à tous,

Le problème c'est de réussir à concaténer un float avec un texte en guillemets. Le float (t) doit être convertit en string (celsiusTemp) pour obtenir la requête HTTP ci-dessous:
http.begin("http://192.168.0.71/msg?msg=TEMPERATURE EXTERIEURE:"+ celsiusTemp);

Le problème en détail:

J'ai conçu un afficheur défilant composé de quelques modules matrices led 8x8.
Il est basé sur une puce LOLINV3 qui se connecte à mon réseau wifi.
L'afficheur fonctionne si on envoie un texte codé 'en dur' grâce à une simple requête HTTP comme celle ci-dessous:

http.begin("http://192.168.0.71/msg?msg=BONJOUR A TOUS !"); //HTTP

J'ai à l'extérieur de la maison, un capteur de température/humidité (DHT22) sur un autre ESP8266 connecté lui aussi au réseau wifi. Je souhaite donc envoyer la température extérieure sur mon afficheur défilant à l'aide d'une requête ressemblant à celle-ci:

http.begin("http://192.168.0.71/msg?msg=TEMPERATURE EXTERIEURE:" + celsiusTemp);

Le soucis c'est que la valeur obtenue avec la librairie DHT est un float qu'il faut donc convertir en chaine de caractères.
J'ai essayé le code ci dessous qui utilise la fonction dtostrf mais ça ne fonctionne pas.

Pour l'instant avec ce code j'ai l'erreur: invalid operands of types 'const char [46]' and 'char [7]' to binary 'operator+'

Déclarations des variables:

// Temporary variables
static char celsiusTemp[7];
static char fahrenheitTemp[7];
static char humidityTemp[7];

Dans le loop:

// LECTURE DU SENSOR DE TEMPERATURE DHT22
            float h = dht.readHumidity();
            // Read temperature as Celsius (the default)
            float t = dht.readTemperature();
            // Read temperature as Fahrenheit (isFahrenheit = true)
            float f = dht.readTemperature(true);
// Convertit les valeurs en celciusTemp, fahrenheitTemp et humidityTemp
              float hic = dht.computeHeatIndex(t, h, false);       
              dtostrf(hic, 6, 2, celsiusTemp);             
              float hif = dht.computeHeatIndex(f, h);
              dtostrf(hif, 6, 2, fahrenheitTemp);         
              dtostrf(h, 6, 2, humidityTemp);
// Requête HTTP       
        
        http.begin("http://192.168.0.71/msg?msg=BONJOUR A TOUS !"); //HTTP

Après de longues recherches sur le web, j'en conclu qu'il y aurait un bug qui fait que le char obtenu avec la fonction dtostrf n'est pas compatible avec ce que je veux faire.

Voilà, vous savez tout.
Merci d'avance pour toute aide, je suis coincé depuis plusieurs jours :frowning:

as tu essayé avec sprintf

Bonjour,

La conversion en chaine de caractères avec dtostrf semble correcte (mais tu vas avoir des espaces d'en tête.
Mais on ne voit pas ou tu utilises celciusTemp et humidityTemp.

Merci pour vos réponses.
J'ai repris le code de l'exemple et je lui ai ajouté ce qu'il faut pour lire le DHT22.

Je reprends le code intégral ci dessous:

/**
 * BasicHTTPClient.ino
 *
 *  Created on: 24.05.2015
 *
 */

#include <Arduino.h>

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

#include <ESP8266HTTPClient.h>

#define USE_SERIAL Serial

#include "DHT.h"
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
// DHT Sensor
const int DHTPin = 5;
// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);

// Temporary variables
static char celsiusTemp[7];
static char fahrenheitTemp[7];
static char humidityTemp[7];


ESP8266WiFiMulti WiFiMulti;

void setup() {

    USE_SERIAL.begin(115200);
   // USE_SERIAL.setDebugOutput(true);
   delay(10);
   
 dht.begin();
    USE_SERIAL.println();
    USE_SERIAL.println();
    USE_SERIAL.println();

    for(uint8_t t = 4; t > 0; t--) {
        USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
        USE_SERIAL.flush();
        delay(1000);
    }

    WiFiMulti.addAP("$$$", "********");

}

void loop() {
    // wait for WiFi connection
    if((WiFiMulti.run() == WL_CONNECTED)) {

        HTTPClient http;

        USE_SERIAL.print("[HTTP] begin...\n");


// LECTURE DU SENSOR DE TEMPERATURE DHT22
            float h = dht.readHumidity();
            // Read temperature as Celsius (the default)
            float t = dht.readTemperature();
            // Read temperature as Fahrenheit (isFahrenheit = true)
            float f = dht.readTemperature(true);
// Convertit les valeurs en celciusTemp, fahrenheitTemp et humidityTemp
              float hic = dht.computeHeatIndex(t, h, false);       
              dtostrf(hic, 6, 2, celsiusTemp);             
              float hif = dht.computeHeatIndex(f, h);
              dtostrf(hif, 6, 2, fahrenheitTemp);         
              dtostrf(h, 6, 2, humidityTemp);


// Requête HTTP       
        
        http.begin("http://192.168.0.71/msg?msg=TEMPERATURE:" + celsiusTemp ); //HTTP

        USE_SERIAL.print("[HTTP] GET...\n");
        // start connection and send HTTP header
        int httpCode = http.GET();

        // httpCode will be negative on error
        if(httpCode > 0) {
            // HTTP header has been send and Server response header has been handled
            USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);

            // file found at server
            if(httpCode == HTTP_CODE_OK) {
                String payload = http.getString();
                USE_SERIAL.println(payload);
            }
        } else {
            USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
        }

        http.end();
    }

    delay(60000);
}

N'utilisez pas la classe String vous aurez des désagréments. (Par exemple "toto" + val ne fabrique pas un objet String, faudrait que "toto" soit déjà dans une instance de la classe String)

Si vous ne pouvez pas envoyer en 2 fois votre requête http (vous ne dites pas quelle librairie vous utilisez) Mettez la chaine de caractère (avez vous besoin du http:// ?) "http://192.168.0.71/msg?msg=TEMPERATURE EXTERIEURE:" dans un buffer assez grand pour stocker cette chaine plus les x chiffres de votre température (au fait ça sert à rien d'afficher 2 chiffres après la virgule votre capteur n'est pas si précis). Vous pouvez le faire avec la fonction standard strcpy()

Puis bâtissez la chaîne avec dtostrf() comme vous le faites dans un autre buffer

Enfin utilisez la fonction strcat() pour la rajouter à la fin du premier buffer.

Là vous pouvez passer ce buffer à votre fonction http

autant pour moi je viens de voir ou tu utilises ces chaines.
il faut que tu crées une chaine en concaténant les deux parties

 char str[100];
  strcpy(str, "http://192.168.0.71/msg?msg=TEMPERATURE EXTERIEURE:");
  strcat(str, celsiusTemp);
  http.begin(str);

edit: je viens de voir que c'est exactement ce qu'a dit J-M-L

rjnc38:
as tu essayé avec sprintf

Je viens de tester et j'ai aussi une erreur:

invalid operands of types 'const char [29]' and 'char [7]' to binary 'operator+'

Le code utilisé:

// Convertit les valeurs en celciusTemp, fahrenheitTemp et humidityTemp
              float hic = dht.computeHeatIndex(t, h, false);       
              //dtostrf(hic, 6, 2, celsiusTemp);             
              sprintf(celsiusTemp, "T: %.2f", hic);
              float hif = dht.computeHeatIndex(f, h);
              dtostrf(hif, 6, 2, fahrenheitTemp);         
              dtostrf(h, 6, 2, humidityTemp);


// Requête HTTP       
        
        http.begin("http://192.168.0.71/msg?msg=" + celsiusTemp); //HTTP

@Kamil - oui c'était ma suggestion (mais je voulais le laisser regarder la doc pour la syntaxe plutôt que de recopier sans comprendre)

@Pascalinus - cf min post plus haut

Quand on poste du code ou une errreur c'est beaucoup plus pertinent de donner TOUT le code et TOUT le message d'erreur avec la ligne qui correspond... votre pb n'est sans doute pas là où vous le pensez

D'autre part sprintf ne gère pas les float sur arduino

J-M-L:
@Kamil - oui c'était ma suggestion (mais je voulais le laisser regarder la doc pour la syntaxe plutôt que de recopier sans comprendre)

Oups désolé :-[
Je ne spoilerai plus tes messages. J’essaierai de ne plus spoiler tes messages.

Pas de pb :slight_smile: ce n'est pas grave. Vous apportez de la valeur c'est ce qui compte, mais pour les débutants je pense que c'est important de les laisser chercher un peu en leur donnant les pistes - meilleur moyen de devenir autonome rapidement

J-M-L:
Pas de pb :slight_smile: ce n'est pas grave. Vous apportez de la valeur c'est ce qui compte, mais pour les débutants je pense que c'est important de les laisser chercher un peu en leur donnant les pistes - meilleur moyen de devenir autonome rapidement

Rester bloqué 2 jours sur un problème comme celui là n'est pas très formateur, c'est même carrément démotivant et c'est la raison pour laquelle je recherche une solution à mon problème.
j'ai déjà épluché des dizaines de pages sur le web sans succès et la suite va vous convaincre que le problème est assez ardu:

Cela étant dit, j'ai essayé la solution de kamil

kamill:
autant pour moi je viens de voir ou tu utilises ces chaines.
il faut que tu crées une chaine en concaténant les deux parties

 char str[100];

strcpy(str, "http://192.168.0.71/msg?msg=TEMPERATURE EXTERIEURE:");
 strcat(str, celsiusTemp);
 http.begin(str);




edit: je viens de voir que c'est exactement ce qu'a dit J-M-L

Avec ce code, je n'ai plus d'erreur à la compilation mais uniquement le mot TEMPERATURE qui défile sur mon afficheur.
C'est très curieux, le reste est tronqué, il y a là quelquechose de très bizarre...

Pour voir ce qui se passe, il faut afficher tes variables (en particulier str) avec un Serial.println() sur le moniteur série.

Faut pas non plus chercher midi à 14h, deux pistes simples :

  • travailler avec des entiers : tu envois ton float multiplié par une puissance de 10 que tu redivises à l'arrivé. Pour l'afficheur il suffit de définir des balises pour qu'il traite ce message différemment.
  • décomposer la partie entière et décimale, utiliser les fonctions de conversion d'entier pour recomposer la chaine de caractère.
char buffer[20];
memset(buffer,NULL,sizeof(buffer));

float val = 6.2;

int partieEntière = int(val);
int partieDecimale = (val - partieEntière) * 10.0

char temp[10];
itoa (partieEntiere,temp,10);
strcat(buffer,temp);
strcat(buffer,".");
itoa (partieDecimale,temp,10);
strcat(buffer,temp);

Bonjour,
Pour l'utilisation de dtostrf, il faut également préciser la longueur du float et du nombre de chiffre après le séparateur décimal.

kamill:
Pour voir ce qui se passe, il faut afficher tes variables (en particulier str) avec un Serial.println() sur le moniteur série.

J'avais devancé ton idée.
Mon afficheur refuse les espaces.
Il faut les convertir en caractère '+'

J'ai tenté un str.replace(" ", "+"); avant d'envoyer la requête mais j'ai une erreur request for member 'replace' in 'str', which is of non-class type 'char [100]'

Je n'en peux plus de ces erreurs auxquelles je ne comprends rien.
Elles ne sont vraiment pas très parlantes pour moi...

Bon, mon problème avance et j'e remercie tout le monde.

J'ai découvert que mon afficheur n'apprécie pas les caractères 'espace'.
Il faut les remplacer par un caractère '+' dans la chaine str avant de lancer la requête...

Voici ce que j'envoie actuellement à l'afficheur ce qui explique que la température n'est pas affichée:

http://192.168.0.71/msg?msg=TEMPERATURE+EXTERIEURE:+ 21.24

Pour retirer l'espace dans la chaine j'ai tenté deux choses sans succès:

Un str.replace(" ", "+"); pour remplacer les " " de la chaine str par des '+' mais j'ai l'erreur ci dessous:
request for member 'replace' in 'str', which is of non-class type 'char [100]'

J'ai aussi tenté un celsiusTemp.substring(1) pour supprimer le premier caractère de celsiusTemp qui est un espace mais là aussi j'ai une erreur que je suis incapable d'interpréter:
request for member 'substring' in 'celsiusTemp', which is of non-class type 'char [7]'

Il faut remplacer les caractères un par un

  while (char *p=strchr(str,' '))
    *p='+';

Recherche un espace et tant qu'on en trouve le remplace par +.

kamill:
Il faut remplacer les caractères un par un

  while (char *p=strchr(str,' '))

*p='+';



Recherche un espace et tant qu'on en trouve le remplace par +.

Merci pour ton aide.
Après des dizaines d'essais de toutes sortes, je me suis souvenu qu'un char est un tableau.
J'ai donc remplacé directement le caractère 'espace' qui se trouve à la position 52 par un '+' : str[52] = '+';

Ta solution est plus élégante, je vais essayer de la mettre en place.

Je trouve que les chaines de caractères sont super mal gérées sous arduino.
On ne retrouve même pas les fonctions essentielles pour parcourir simplement une chaine et remplacer des caractères. toutes ces erreurs sont incompréhensibles. Des char qui n'en sont pas vraiment, des string qui ne sont pas des char non plus... bref, je patauge dans tout ça mais finalement ça fonctionne.

Merci à tous.

pascalibus:
Je trouve que les chaines de caractères sont super mal gérées sous arduino.

Ce sont des chaines C qui sont des bêtes tableaux de char terminés par 0.
Il faut tout gérer avec des fonctions de bas niveau.

Suivant le environnements il existe des chaines plus élaborées.
Sous arduino c'est la class String qui fait une gestion de plus haut niveau (en particulier +)
Ce qu'on peut reprocher à ces chaines c'est que c'est consommateur de ressources et sur un petit micro comme les AVR ce peut être pénalisant.