Go Down

Topic: Simulateur de présence (modifié avec utilisation de Painless Mesh)  (Read 1 time) previous topic - next topic

MicroQuettas

Bravo pour cette belle réalisation et merci de l'avoir publiée.

Pour la soudure de fils sur des pastilles très fines comme c'est le cas pour "hacker" les prises Sonoff, j'utilise du fil émaillé de 2/10. Il est très souple et cela diminue le risque d'arracher les pastilles.

Pour le découpage d'un programme en "modules" constitués chacun d'un fichier .h et .cpp, j'y suis arrivé pour mes projets, mais ce n'est pas vraiment simple et demande une grande rigueur. J'avais fait une ébauche de recette de cuisine, mais elle n'est plus à jour... Je vais la mettre à jour et la publier... mais sans promesse ferme...

Bonne bidouille

MicroQuettas

lesept

#16
Aug 17, 2019, 04:55 pm Last Edit: Aug 18, 2019, 12:52 pm by lesept
Je reprends le fil avec une version basée sur la bibliothèque Painless Mesh. Le but de cette bibli est de fournir des outils pour créer un réseau "mesh", c'est à dire un réseau maillé, au sein duquel les messages transitent d'un nœud à l'autre en étant parfois renvoyés par d'autres nœuds.



Du coup, il est possible d'étendre le réseau sur une plus grande distance ou dans un endroit où le wifi passe mal, du fait de cette retransmission. Ainsi, si le nœud A envoie un message au nœud D, il peut passer par le B et le C avant de lui arriver.

Bref, la bibli permet de créer facilement ce genre de réseau. Elle est toujours en évolution, mais la version actuelle 1.4.2 est assez stable.

Mon application est de faire une simulation de présence dans un endroit qui n'est pas habité. J'utilise des prises commandées Sonoff S26 et un ESP32 comme chef d'orchestre. La prise coûte près de 8€ chez Ali,bien choisir la prise adaptée à la France (modèle EU E, pas F).



Le code est donc en 2 parties : une pour les prises, et une pour l'ESP32. L'ESP32 joue le rôle de coordinateur du réseau, mais aussi de passerelle vers Internet, via la box, pour pouvoir contrôler l'état des prises en temps réel et les commander le cas échéant. Un écran OLED est attaché à l'ESP32 pour donner une vue synthétique de l'état des prises.

Il y a donc 3 couples identifiant / password dans cette appli :
  • Connexion des prises et de l'ESP32 au réseau mesh (il doit être le même dans le code des prises)
  • Connexion de l'ESP32 au Wifi
  • Connexion sécurisée sur l'ESP32 pour le contrôle à distance


Je commente ici le code de l'ESP32 (attaché).
C'est lui qui définit les intervalles d'allumage de chaque prise (que j'appelle slots). Ils sont définis par une struct qui contient :
Code: [Select]
typedef struct {
  byte device;
  byte days : 7;   // binary 0bSMTWTFS (Sunday, Monday, Tuesday ... Saturday) - use 7 bits
  byte hourBegin;  // 0 ... 23
  byte minBegin;   // 0 ... 59
  byte hourEnd;
  byte minEnd;
  byte randomMin;  // randomly add or decrease begin and end times of up to xx minutes
} TimeSlot;

  • Le numéro de la prise associée
  • Les jours concernés : DLMMJVS (de Dimanche à Samedi), en binaire sur 7 bits: 0b1001010 signifie Dimanche, Mercredi et Vendredi
  • L'heure d'allumage : heure (0 - 23) et minutes (0 - 59)
  • L'heure d'extinction (idem : attention à bien définir une heure de fin après l'heure de début)
  • Un intervalle (en minutes) aléatoire qui s'ajoute ou se retranche aux heures précédentes pour ne pas avoir de répétition trop franche d'un jour sur l'autre (0 : horaires fixes)

Le numéro de la prise peut être remplacé par les éléments d'un enum, comme par exemple
Code: [Select]
enum device_t : byte {Salon, Cuisine, Bureau, SalleDeBain, ChLea, ChIrena, WC, Entree};
La prise 0 serait équivalente à Salon, 1 Cuisine, etc.

Un exemple de slot :
Code: [Select]
{Salon, 0b1010101, 20, 10, 20, 50, 10}
La prise du Salon s'allumera les Dimanche, Mardi, Jeudi et Samedi, de 20h10 +- random(10) minutes à 20h50 +- random(10) minutes, random(10) étant un nombre aléatoire entre 0 et 10. Les horaires peuvent être par exemple 20h03 à 20h56.

Evitez de définir un trop grand nombre de slots, car on peut avoir des problèmes de mémoire. J'ai eu des soucis autour de 60... Je travaillerai plus tard sur une solution pour régler ça.

Pour l'affichage web ou OLED, il est possible de définir des noms spécifiques aux prises, par exemple "Salon", 'Cuis.", etc.

Le montage électronique est très simple : ESP32 - OLED sur I2C (SCL 22, SDA 21). L'écran affiche de manière synthétique l'état de chaque prise et son nom :
  • ON : petit cercle plein (comme une lumière allumée)
  • OFF : petit cercle vide
  • Inconnu : cercle barré



L'ESP32 abrite un server web, avec une adresse IP fixe : il est accessible sur un browser via :
Code: [Select]
http://192.168.0.51:81
J'ai choisi le port 81 car j'ai parfois un RPi sur le port 80, mais ça peut être changé dans le code. La connexion est authentifiée et demande l'identifiant et le password défini plus haut.

L'écran principal affiche l'état des prises :
  • Rectangle vert, état ON : prise allumée
  • Rectangle rouge, état OFF : prise éteinte
  • Rectangle bleu : prise non connectée

Si la prise est allumée, rectangle vert, on peut l'éteindre en cliquant sur le mot 'OFF' à l'intérieur du rectangle. De même si la prise est éteinte. Si elle n'est pas connectée, le rectangle n'est pas cliquable. Je sais, ça peut être trompeur de voir ON à l'intérieur du rectangle rouge (prise éteinte), mais juste au dessus est écrit "Status OFF"... C'est un choix...



En cliquant sur le nom de la prise, on accède à la liste des slots qui lui sont associés. Ça permet de connaitre à distance les jours et horaires (et leur partie aléatoire) d'allumage.


Enfin, en cliquant sur le titre de la page principale, on accède à la liste des prises, avec leur numéro 'mesh', leur nom, et si elles sont forcées ou non.

Prise forcée : si on clique sur un rectangle vert ou rouge, on force l'allumage ou l'extinction d'une prise. Elle va rester dans cet état jusqu'à ce qu'on change d'état en cliquant une nouvelle fois, ou qu'un slot du même état se termine.
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

lesept

#17
Aug 17, 2019, 04:56 pm Last Edit: Sep 20, 2019, 07:11 pm by lesept
Le code des prises est en pièce jointe.

Il organisé en fonctions :
  • Callbacks en cas d'événement Painless Mesh (connexion, message entrant)
  • Blink pour faire clignoter la led
  • Fonction pour indiquer le numéro d'ordre de la prise avec le bouton poussoir (à l'initialisation)
  • Fonction de changement d'état en cas d'appui sur le bouton (allumer ou éteindre la prise par un appui sur le bouton)
  • Setup : initialisation du réseau mesh
  • Loop : surveillance du bouton en cas de changement d'état

L'avantage de Painless Mesh est que la loop n'a pratiquement rien à faire : tout est fait par les fonctions Callback, en l'occurrence ici traiter un message entrant et y répondre.

Les messages entrants sont très simples :
  • ON : ordre d'allumage de la prise,
  • OFF : ordre d'extinction,
  • GET : demande d'envoi d'information d'état,
  • SET : ordre de mise à jour de l'Id de la prise,
  • BLINK : ordre de clignotement de la led.

La fonction de choix du numéro de la prise est plus complexe : elle permet après branchement de la prise de choisir son numéro (puis de l'envoyer à l'ESP32 qui saura ainsi de quelle prise il s'agit, et donc où elle se trouve). L'utilisateur a 15 secondes pour appuyer N fois sur le bouton (N étant le numéro d'ordre choisi).
Si aucun appui n'est fait au bout de 2 secondes, le décompte s'arrête.

Un appui sur le bouton de la prise permet de forcer son état ON ou OFF.
Dans cette version, plus de serveur pour accéder à la prise et la commander : c'est l'ESP32 qui commande toutes les prises via Painless Mesh.
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

lesept

#18
Aug 17, 2019, 04:56 pm Last Edit: Sep 12, 2019, 07:18 pm by lesept
J'ai envisagé de faire une version du code sans utiliser la classe String, qui pourrait poser des problèmes de fragmentation de la mémoire à long terme. Mais, après une série de tests sans aucun problème sur plus de 2 semaines, je pense que ce n'est pas nécessaire.

Donc, sauf demande expresse ou temps libre, je ne pense pas la développer...
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

lesept

Je me suis aperçu que l'ESP32 perd assez souvent la connexion internet, ce qui rend impossible la consultation de l'état des prises à distance. Par contre, Painless Mesh a l'air protégé contre les déconnexions, et le contrôle des prises continue donc quand même.

Pour pallier à ce problème, j'ajoute une vérification de l'état de connexion au Wifi toutes les 20 secondes :

Ajout d'une déclaration de variable dans l'en-tête :
Code: [Select]
bool checkWiFi = true;

Et de la vérification dans la loop :
Code: [Select]
void loop() {
  //  userScheduler.execute();
  mesh.update();

  if (myIP != mesh.getStationIP()) {
    myIP = mesh.getStationIP();
    Serial.println("\nServer -> connect to " + myIP.toString() + ":81");
    Serial.print("------------------------------------\n");
  }

  getLocalTime(&timeinfo);
  // verify WiFi connection @ seconds 5, 25 & 45
  if (timeinfo.tm_sec % 20 == 5) {
    if (checkWiFi) {
      if (WiFi.status() != WL_CONNECTED) wifiConnect();
      checkWiFi = false;
    }
  } else checkWiFi = true;

  //  do nothing until next plain minute (seconds == 0)
  if (timeinfo.tm_sec == 0) {
    if (!isVerified) {
      int timeNow = timeinfo.tm_hour * 60 + timeinfo.tm_min;
      if (timeNow == 0) setTimesBE (); // update slots at midnight
      Serial.printf ("\nTime : %d (%02d:%02d:%02d)", timeNow, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
      verifyDevices (timeNow);
    }
  } else isVerified = false;
}
Depuis cette modification, plus aucun problème, si ce n'est des demandes de login / pass parfois lorsque je veux vérifier l'état des prises.
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

lesept

Voici la version finale du code pour le contrôleur sur ESP32. Le code des prises ne change pas.
Bonne utilisation à ceux qui voudraient tester, et n'hésitez pas à me contacter si vous avez des questions ou à réutiliser tout ou partie des codes.
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

al1fch

Bonsoir

Peux-tu dire en quelques mots l'apport de  'Painless Mesh'  à ton application  par rapport à la structure antérieure ?

lesept

D'accord la structure du réseau. Avant j'avais des devices individuels tous connectés à ma box en WiFi. J'aurais pu aussi faire un réseau en étoile autour de l'esp32 en point d'accès, mais je voulais pouvoir commander chaque prise via un serveur Web hébergé par chacune.

Avec Painless mesh, j'ai un réseau maillé, dans lequel je peux ou non définir un nœud principal. L'intérêt est que les messages sont routés de nœud en nœud donc la communication est plus sûre et l'étendue du réseau est supérieure.
L'un des nœuds héberge l'unique serveur et communique avec les autres devices. Les communications sont plus simples et la bibliothèque prend en charge le protocole, la gestion des messages, la découverte des nouveaux devices, etc. C'est le nœud central qui est connecté à la box pour fournir l'IHM de contrôle ou de gestion des prises. C'est plus simple.
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

al1fch

Merrci pour ce complément d'explications  et pour cette réalisation inovante qui met au grand jour  une fonctionnalité méconnue des ESP8266 et ESP32, qui ne font pas que du  WiFi 'pur et dur' !

Dernière question : as tu une idée du comportement,  d'un appareil (autre qu'une prise Sonoff) , alimenté par une batterie, qui serait la plupart du temps en sommeil profond et se réveillerait de temps à autre pour rejoindre le réseau maillé ?
Que se passe-t-il quand tu débranches une prise Sonoff et que tu la rebranches ? En cas de coupure secteur ?

Il  serait utile de pouvoir retrouver  , sans action manuelle, sa place dans le réseau maillé ?
ça pafait faisable en modifiant ta fonction idButton de la manière suivante :

si une Id valide est présent en EEPROM on l'utilise sinon on se donne 15s pour en définir une avec le bouton et on la mémorise en EEPROM



lesept

Oui, Painless Mesh gère la disparition et l'apparition de noeud du réseau. Si un nouveau noeud se connecte au réseau, parce tu branches une nouvelle prise par exemple, il rejoint le réseau et les autres nœuds sont avertis. Un callback est généré et tu peux définir une fonction qui sera exécutée à ce moment là.

J'ai constaté cependant que ce n'est pas forcément immédiat, il peut se passer plusieurs secondes voire dizaines de secondes avant que le nœud soit détecté et la fonction exécutée.

 Un appareil qui se mettrait en sommeil et se réveillerait ne quitterait pas le réseau, j'imagine qu'il continuerait à fonctionner comme avant au sein du réseau, mais qu'il aurait simplement loupé les messages échangés pendant son sommeil.
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

al1fch

je pensais à la reconnection répétitive d'une prise et non à la connection d'une nouvelle

lesept

J'ai édité ma réponse pendant ton message...

J'ai remarqué qu'un noeud qui quitte le réseau et s'y reconnecte ne change pas d'identifiant.
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

al1fch

inrtéressant !! (l'adresse MAC est peut être utilisée en arrière plan)
Et après une coupure secteur tu n'a pas à jouer du bouton poussoir sur chaque prise , tout se remet tout seul en place 'comme avant'  , même si tous les partenaires ont été privés de courant ?

lesept

Dans mon cas : si. Il faut reconfigurer les prises avec le BP, pour leur donner un numéro à chacune. Sinon, elles auront toutes le numéro 0 et l'ESP32 sera perdu... Je pourrais sauver le numéro dans l'EEPROM, je n'y avais pas pensé...
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

lesept

Voici les versions encore plus finales que finales des codes :

Prise : sauvegarde du numéro dans l'EEPROM pour relance automatique en cas de coupure de courant. En cas de coupure, le code se relance, charge le numéro sauvegardé en EEPROM s'il y en a un, attend 15 secondes si l'utilisateur veut lui donner un numéro et entre ensuite dans la boucle d'attente normale des commandes en provenance du réseau.
Si aucun appui sur le bouton, la prise garde le numéro mémorisé en EEPROM. Donc pour donner le numéro 0, il faut appuyer 8 fois sur le bouton (si vous avez conservé 8 comme valeur de numberOfDevices dans le code). Le numéro sélectionné est égal au nombre d'appuis modulo cette valeur (ce qui permet de corriger si on se rate)...

Contrôleur ESP32 : j'ai changé l'algorithme de mise à jour de l'état des prises, afin de mieux gérer les plages horaires (slots) d'allumage situés autour de minuit. L'algorithme actuel cherche pour chaque prise le slot actuel (celui qui contient l'heure courante) ou s'il n'y en a pas le slot suivant. Ca simplifie beaucoup par rapport à l'ancien algorithme qui cherchait constamment le slot courant : la recherche se fait au lancement et au changement de jour, et il n'y a qu'une mise à jour à faire lorsque le slot actuel est terminé.

Bref, voici les codes finaux de chez finaux...
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

Go Up