Gestion On/off sur Esp8266 via MQTT

Forum dédié au protocole MQTT : fonctionnement, intégration ...
Pour les questions concernant le plugin de FlyingDomotic, merci d'utiliser le sous-forum dédié.
Flying Domotic
Messages : 772
Inscription : 10 mars 2020, 15:26

Re: Gestion On/off sur Esp8266 via MQTT

Message par Flying Domotic »

Pour la RTC, il semble qu'il faille l'initialiser à une date non nulle avant de l'utiliser par un rtctime.set(). De plus, il est habile de le resynchroniser de temps en temps par un sntp.sync().

Sinon, quel est le pb avec le compteur ?

Avec MQTT, le plus simple est d'envoyer le compteur sous forme de string.

L'idée globale est d'enregistrer manuellement une valeur initiale, avec l'option "Retain".

Dans l'ESP, souscrire au topic du compteur. Lorsqu'on reçoit le topic, on l'incrémente et le republie avec la nouvelle valeur, toujours avec le flag "Retain".

De l'extérieur, on consulte le topic du compteur de temps en temps, et on regarde si ça change. si c'est le cas, c'est que l'ESP est s'est bien (re)connecté sur MQTT, et qu'il arrive à lire et écrire. Sinon, y'a un blème ;-)

Ca marche aussi bien pour un compteur incrémental que la date. Si on est joueur, on peut même utiliser une fonction "random" et écrire une valeur au hasard (à condition de vérifier qu'on initialise bien le random, par exemple avec une valeur lue sur A0 laissée en l'air).
pierrotori
Messages : 821
Inscription : 29 févr. 2016, 12:11

Re: Gestion On/off sur Esp8266 via MQTT

Message par pierrotori »

const char* msg_veille=".";
StaticJsonDocument<200> doc;

pour mon problème de vatiable , j'ai dans le topic : { "value": "1"}
je fais ca pour le récupérer dans une variable de type

Code : Tout sélectionner

    if (String(topic) == mqtt_veille) {
      DPRINT("Valeur veille : ");
      DPRINTLN(messageTemp);
      // Deserialize the JSON document
      DeserializationError error = deserializeJson(doc, messageTemp);
      // Test if parsing succeeds.
    if (error) {
      DPRINT(F("deserializeJson() failed: "));
      DPRINTLN(error.f_str());
      return;
    }
      if (messageTemp == "") { msg_veille="."; }
      if (messageTemp != "") { msg_veille = doc["value"]; }
      DPRINT("Valeur lue : ");
      DPRINTLN(msg_veille);      
    }
ensuite je fais ca alors que la variable contient bien 1

Code : Tout sélectionner

          compteur=(int)(msg_veille)+1;
          sprintf(mqttbuffer_var,"{ \"value\" : \"%d\" }", compteur );
          client.publish(mqtt_veille, mqttbuffer_var, true);
et je me retrouve avec cette valeur : { "value": "1073671623"}
si j'arrive à le faire fonctionner je pourrais le faire sur la date et heure pour voir l'évolution des connections
pierrotori
Messages : 821
Inscription : 29 févr. 2016, 12:11

Re: Gestion On/off sur Esp8266 via MQTT

Message par pierrotori »

je viens de trouver pour caster

Code : Tout sélectionner

          sscanf(msg_veille, "%d", &compteur);
          compteur=compteur+1;          
          sprintf(mqttbuffer_var,"{ \"value\" : \"%d\" }", compteur );
Flying Domotic
Messages : 772
Inscription : 10 mars 2020, 15:26

Re: Gestion On/off sur Esp8266 via MQTT

Message par Flying Domotic »

Effectivement, il vaut mieux récupérer une valeur numérique avant l'incrémentation.

Au niveau du code, il peut être intéressant d'utiliser "else" dans :

Code : Tout sélectionner

if (messageTemp == "") { msg_veille="."; }
if (messageTemp != "") { msg_veille = doc["value"]; }
qui deviendrait :

Code : Tout sélectionner

if (messageTemp == "") {
    msg_veille = "0";
} else {
    msg_veille = doc["value"];
} 
Etant donné qu'on va convertir msg_veille en nombre, il peut être utile de lui donner une valeur numérique comme "0" plutôt que "." s'il n'est pas défini.

De même, protéger

Code : Tout sélectionner

sprintf
par un

Code : Tout sélectionner

snprintf
snprintf, voire un

Code : Tout sélectionner

snprintf_P
, qui éviteront des soucis si le buffer mqttbuffer_var est trop court.

Ceci dit, on peut aussi créer le message de sortie par la classe ArduinoJson :

Code : Tout sélectionner

DynamicJsonDocument jsonDoc(50);
jsonDoc["value"] = compteur;
String jsonMessage;
serializeJson(jsonDoc, jsonMessage);
client.publish(mqtt_veille, jsonMessage, true);
pierrotori
Messages : 821
Inscription : 29 févr. 2016, 12:11

Re: Gestion On/off sur Esp8266 via MQTT

Message par pierrotori »

Sympa la class Json pour créer une chaîne , du coup je peux faire jsonDoc["value"] = compteur;et jsonDoc["update"] = date;
merci pour l'info

Le compteur c'est bien mais ce n'est pas très parlant,
Je pourrais initialiser une date rtc_date dans mon topic veille avec la date du rtc au démarrage ou date de compilation et l'incremeter avec la durée cyclique de réveil de l'esp jusqu'à ce que la date de l'action existe (période très courte)

Pour rappel j'ai un topic action avec l'action demandée on ou off avec la date de l'action
Et un autre topic status avec l'action on ou off en cours et la date du status

Quand arrive ma demande d'action et qu'elle est différente du status alors je synchronise la rtc_date, ce qui veut dire que dans mon utilisation elle sera faite 2 fois par jour, le reste du temps elle sera incrementee

Cette gestion me permettra de voir que l'esp même en veille se connect même si il n'y a pas de demande car mon réseau a un niveau 1 la où se trouve l'esp
Je ne sais pas si la solution est bonne ou consommatrice mais de tout façon l'esp a chaque fois qu'il se réveille se connect au wifi et au mqtt, qu'en penses tu @flying ? As tu mis en place ce type de gestion ou une autre ?
Flying Domotic
Messages : 772
Inscription : 10 mars 2020, 15:26

Re: Gestion On/off sur Esp8266 via MQTT

Message par Flying Domotic »

De mon côté, je n'utilise pas trop la veille sur ESP. Si j'ai besoin d'un truc qui ne consomme pas trop, j'utilise plutôt un CC2652RB (ZigBee), qui possède un processeur séparé pour gérer les E/S et le temps, et ne réveiller le processeur principal que lorsqu'il y a besoin d'envoyer/recevoir des choses.. Côté consommation, c'est vraiment faible. Par contre, c'est pas forcement très simple à mettre en œuvre.

Sinon, pour monitorer MQTT, j'utilise un netstat sur le port 1883, et vérifie que les IP qui m'intéressent sont bien connectées. Dans ton cas, ça risque de ne pas trop le faire ...
pierrotori
Messages : 821
Inscription : 29 févr. 2016, 12:11

Re: Gestion On/off sur Esp8266 via MQTT

Message par pierrotori »

Quand on a un topic qui contient cela
{
"value": "1.57",
"update": "2023-05-06 16:00"
}

si on veut remettre à jour uniquement la date c''est possible ou il faut réécrire la chaine complète ?
Flying Domotic
Messages : 772
Inscription : 10 mars 2020, 15:26

Re: Gestion On/off sur Esp8266 via MQTT

Message par Flying Domotic »

Ben ça dépend de la manière dont c'est traité ensuite. SI le(s) code(s) qui traie(nt) le topic s'attende(nt) à trouver les deux, la réponse est oui. Sinon ... c'est non.

Je dirais, dans le doute, qu'il vaut mieux réécrire le tout, surtout si le topic à une option "retain".

D'autant que si on le lit avant, il suffit juste de modifier l'item "udate" et de réécrire ce qu'on a lu avec cette modif.
pierrotori
Messages : 821
Inscription : 29 févr. 2016, 12:11

Gestion On/off sur Esp8266 via MQTT

Message par pierrotori »

Je galère a récupérer plusieurs topics dans la fonction callback avec json a cause des pointeurs de la fonction deserialization et les déclarations des variables char* ou char
Est ce quelqu’un pourrait mettre son code de la callback pour m’aider ?
Flying Domotic
Messages : 772
Inscription : 10 mars 2020, 15:26

Re: Gestion On/off sur Esp8266 via MQTT

Message par Flying Domotic »

Par exemple :

Code : Tout sélectionner

void mqttMessageCallback(const char *topic, const char *payload, const AsyncMqttClientMessageProperties properties, const size_t len, const size_t index, const size_t total)
    char localPayload[250];
    size_t localSize = sizeof(localPayload);

    if (len < localSize) localSize = len;                   // Maximize len to copy
    memset(localPayload, '\0', sizeof(localPayload));
    strncpy(localPayload, payload, localSize);

	trace_info_P("Received MQTT message %s on topic %s, len %d, index%d, total %d", localPayload, topic, len, index, total);

	// Check for long (multi packets) messages
	if (len != total) {
		trace_error_P("Can't deal with multi packet messages!");
		return;
	}
	// Analyze JSON message
	DynamicJsonDocument jsonDoc(MAX_SMS_MESSAGE_LEN);
	auto error = deserializeJson(jsonDoc, localPayload);
	if (error) {
		trace_error_P("Failed to parse %s. Error: %s", localPayload, error.c_str());
		return;
	}
	// Analyze topic
	if (mqttGetTopic) {										// Is mqttGetTopic defined?
		if (String(topic) == mqttGetTopic) {				// Is it the right topic?
			String message = jsonDoc["message"].as<const char *>();
			String number = jsonDoc["number"].as<const char *>();
			if (message == "" && number == "") {			// Check for message and number
				trace_error_P("Message and number missing from MQTT payload %s for topic %s", localPayload, topic);
				return;
			}
			if (message == "" ) {							// Check for message
				trace_error_P("Message missing from MQTT payload %s for topic %s", localPayload, topic);
				return;
			}
			if (number == "") {								// Check for number
				trace_error_P("Number missing from MQTT payload %s for topic, %s", localPayload, topic);
				return;
			}
			sendSMS(number.c_str(), message.c_str());		// Ok, store the SMS in queue
		}
	}
	trace_error_P("Unknown topic %s received!", topic);
}
Répondre