C'est le printemps ! Fleur.gif

Passerelle.Infini 2025 : MOUMOUNAN : Différence entre versions

De Les Fabriques du Ponant
Aller à : navigation, rechercher
(membres du projet)
(code)
Ligne 66 : Ligne 66 :
 
==code==
 
==code==
 
<syntaxhighlight lang="Arduino" line>  
 
<syntaxhighlight lang="Arduino" line>  
/////////////////////////
+
/////////////////////////////
//      POCL Poke     //
+
//      Moumouna     //
/////////////////////////
+
/////////////////////////////
 
/*
 
/*
  * Un POCL imaginé et réalisé au Hackathon POCL à l'édulab Rennes 2 les 9 et 10 décembre 2021.
+
  * Un projet imaginé et réalisé au Hackathon Passerelle.Infini organisé avec les petits débrouillards au centre d'art Passerelle à Brest les 20 et 21 mars 2025.
 +
* moumouna : https://wiki.lesfabriquesduponant.net/index.php?title=Passerelle.Infini_2025_:_MOUMOUNAN
 +
*
 +
* Ce programme s'apuie sur le programme POCL Poke (imaginé et réalisé au Hackathon POCL à l'édulab Rennes 2 les 9 et 10 décembre 2021).
 +
* POCL Poke : https://wiki.lesfabriquesduponant.net/index.php?title=POCL_:_Poke
 
  *  
 
  *  
* Difficultés :
 
 
  * Configurez le logiciel Arduino pour gérer la carte D1 mini (ESP8266).
 
  * Configurez le logiciel Arduino pour gérer la carte D1 mini (ESP8266).
 
  * Intégrer les biobliothèues requises par le projet :
 
  * Intégrer les biobliothèues requises par le projet :
Ligne 79 : Ligne 82 :
 
  ** #include <WiFiManager.h> -> Bibliothèque WiFiManager pour configurer automatiquement le réseau wifi et le mot de passe.
 
  ** #include <WiFiManager.h> -> Bibliothèque WiFiManager pour configurer automatiquement le réseau wifi et le mot de passe.
 
  *  
 
  *  
  *                                     BROCHAGE                             
+
  *                                   BROCHAGE                             
 
                                 _________________                         
 
                                 _________________                         
 
                               /    D1 mini    \                       
 
                               /    D1 mini    \                       
Ligne 85 : Ligne 88 :
 
                           -  |[ ]A0  -GPIO  RX[ ]| -                     
 
                           -  |[ ]A0  -GPIO  RX[ ]| -                     
 
                               |[ ]D0-16    5-D1[ ]| -                     
 
                               |[ ]D0-16    5-D1[ ]| -                     
                               |[ ]D5-14    4-D2[x]| - Vibreur In                 
+
                               |[ ]D5-14    4-D2[ ]| -                  
 
                     Bouton -  |[X]D6-12    0-D3[X]| - ruban de leds             
 
                     Bouton -  |[X]D6-12    0-D3[X]| - ruban de leds             
                           -  |[ ]D7-13    2-D4[ ]| -         
+
                           -  |[ ]D7-13    2-D4[ ]| LED_BUILTIN         
 
                           -  |[ ]D8-15    GND[X]| - GND (Boutons, ruban de leds)             
 
                           -  |[ ]D8-15    GND[X]| - GND (Boutons, ruban de leds)             
 
                           -  |[ ]3V3 .      5V[X]| - ruban de Led         
 
                           -  |[ ]3V3 .      5V[X]| - ruban de Led         
Ligne 100 : Ligne 103 :
 
- une alimentation 5V
 
- une alimentation 5V
 
*/
 
*/
 
 
/*
 
/*
 
  * Un travail d'équipe de :
 
  * Un travail d'équipe de :
Ligne 116 : Ligne 118 :
 
         ___|_  _|
 
         ___|_  _|
 
         |___| |_|
 
         |___| |_|
Les petits Débrouillards - décembre 2021 CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
+
Les petits Débrouillards - mars 2025 CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
 +
// Programme nourri de https://randomnerdtutorials.com/esp32-esp8266-rgb-led-strip-web-server/
 
// Programme inspiré de celui par Joël Gähwiler
 
// Programme inspiré de celui par Joël Gähwiler
 
// https://github.com/256dpi/arduino-mqtt
 
// https://github.com/256dpi/arduino-mqtt
 +
 +
Améliorations :
 +
reboot en cas de déconnexion MQTT
 +
 
*/
 
*/
 
 
#include <ESP8266WiFi.h>
 
#include <ESP8266WiFi.h>
 
#include <MQTT.h> // Bibliothèque MQTT par Joël Gaehwiler
 
#include <MQTT.h> // Bibliothèque MQTT par Joël Gaehwiler
 
#include <Adafruit_NeoPixel.h> // Bibliothèque NeoPixel d'Adafruit
 
#include <Adafruit_NeoPixel.h> // Bibliothèque NeoPixel d'Adafruit
 
#include <WiFiManager.h> // Bibliothèque WiFiManager pour configurer automatiquement le réseau wifi et le mot de passe.
 
#include <WiFiManager.h> // Bibliothèque WiFiManager pour configurer automatiquement le réseau wifi et le mot de passe.
 +
#include <ESP_EEPROM.h>
  
 
WiFiClient net; //on crée l'objet WiFiClient "Net"
 
WiFiClient net; //on crée l'objet WiFiClient "Net"
MQTTClient client;
+
WiFiServer serveurPOCL(80);
 +
MQTTClient clientMQTT;
 +
#define BROKER_IP "debrouillards.ddns.net" //IP du serveur sur lequel est installé le Broker MQTT
  
#define BROKER_IP "debrouillards.ddns.net" //IP du serveur sur lequel est installé le Broker MQTT
 
 
unsigned long lastMillis = 0;
 
unsigned long lastMillis = 0;
  
//=============élément pour le ruban de led et le bouton===============
+
char nomPOCL[25];        // variable de stockage du nom unique du POCL
 +
 
 +
 
 +
//==============Vibreur======================
 +
const int vib = D2; // broche vibreur
 +
//=============Eléments pour le ruban de led et le bouton===============
  
 
// Broche de connexion du ruban de LED
 
// Broche de connexion du ruban de LED
#define PIN D3
+
#define PIN D3 // Il faudra changer en D2 (broche plus adpatée).
  
const int brocheBouton = 12; //GPIO de la broche D6
+
int brocheBouton = 12; //GPIO de la broche D6
const int vib = D2;
+
int rouge = 0;
 +
int bleu = 255;
 +
int vert = 0;
  
 
// Nombre de Led RDGB dans votre ruban
 
// Nombre de Led RDGB dans votre ruban
#define NUMPIXELS 13
+
#define NUMPIXELS 6
  
 
// on configurer un riban nommé "pixels"
 
// on configurer un riban nommé "pixels"
Ligne 147 : Ligne 162 :
  
 
#define T 1 // temps pour gérer le fade du ruban
 
#define T 1 // temps pour gérer le fade du ruban
 +
//==============================================================
 +
 +
//===============Eléments pour le choix de la couleur du Ruban===============
 +
// Pour décoder les valeurs de HTTP GET
 +
String redString = "0";
 +
String greenString = "0";
 +
String blueString = "0";
 +
int pos1 = 0;
 +
int pos2 = 0;
 +
int pos3 = 0;
 +
int pos4 = 0;
  
//==============================================================
+
// Variable to store the HTTP req  uest
 +
String header;
 +
 
 +
// Setting PWM bit resolution
 +
// const int resolution = 256;
 +
 
 +
// Current time
 +
unsigned long currentTime = millis();
 +
// Previous time
 +
unsigned long previousTime = 0;
 +
// Define timeout time in milliseconds (example: 2000ms = 2s)
 +
const long timeoutTime = 2000;
  
 +
//==============================================================================
 
void connect() {
 
void connect() {
 
   Serial.print("Vérification de la connexion Wifi...");
 
   Serial.print("Vérification de la connexion Wifi...");
Ligne 156 : Ligne 194 :
 
     delay(1000);
 
     delay(1000);
 
   }
 
   }
    
+
   Serial.println("\nPOCL Connecté au Wifi :-) ");
   Serial.print("\nconnexion au serveur MQTT en cours...");
+
   Serial.print("\nconnexion au serveur MQTT en cours ");
 
   //connection au serveur MQTT : identifiant, User, mot de passe
 
   //connection au serveur MQTT : identifiant, User, mot de passe
 
+
   while (!clientMQTT.connect(nomPOCL, "poclpokou", "pokou")) {
   while (!client.connect("Antony", "poclpokou", "pokou")) {
+
     Serial.println(".");
     Serial.print(".");
+
     delay(300);
     delay(1000);
 
 
   }
 
   }
  
Ligne 168 : Ligne 205 :
  
 
// on s'abonne au sujet (topic) "/mou"  
 
// on s'abonne au sujet (topic) "/mou"  
   client.subscribe("/mou"); // Attention à la casse !! La casse c'est maj ou minuscule
+
   clientMQTT.subscribe("/mou"); // Attention à la casse !! La casse c'est maj ou minuscule
 
   Serial.println("Abonné à /mou");
 
   Serial.println("Abonné à /mou");
 
   // client.unsubscribe("/mou");// Pour se désinscrire
 
   // client.unsubscribe("/mou");// Pour se désinscrire
Ligne 177 : Ligne 214 :
 
   fade();
 
   fade();
 
   Serial.println("incoming: " + topic + " - " + payload);
 
   Serial.println("incoming: " + topic + " - " + payload);
 
 
   if (payload == "calin"){
 
   if (payload == "calin"){
 
     Serial.println("clic !");
 
     Serial.println("clic !");
Ligne 185 : Ligne 221 :
 
   }
 
   }
 
}
 
}
 
  
 
void fade() {
 
void fade() {
 +
  EEPROM.get(0, rouge); Serial.print("Valeur de rouge EEPROM = "); Serial.println(rouge);
 +
  EEPROM.get(4, vert); Serial.print("Valeur de vert EEPROM = "); Serial.println(vert);
 +
  EEPROM.get(8, bleu); Serial.print("Valeur de bleu EEPROM = "); Serial.println(bleu);
 +
 
 
   for (int sig=0; sig<3; sig++){
 
   for (int sig=0; sig<3; sig++){
 
   for (int b=0; b<255; b++){
 
   for (int b=0; b<255; b++){
 
   pixels.setBrightness(b);
 
   pixels.setBrightness(b);
 
+
 
 
   for(int i=0; i<NUMPIXELS; i++) {
 
   for(int i=0; i<NUMPIXELS; i++) {
     pixels.setPixelColor(i, pixels.Color(250, 150, b));
+
     pixels.setPixelColor(i, pixels.Color(rouge, vert, bleu));
 
   }
 
   }
 
 
   pixels.show();  // On allume les rubans
 
   pixels.show();  // On allume les rubans
  digitalWrite(vib, HIGH);
 
 
   delay(T);
 
   delay(T);
 
   }
 
   }
Ligne 203 : Ligne 240 :
 
   for (int b=255; b>1; b--){ //boucle de gestion de la brillance
 
   for (int b=255; b>1; b--){ //boucle de gestion de la brillance
 
   pixels.setBrightness(b);
 
   pixels.setBrightness(b);
 
+
 
 
   // n'oubliez pas que le premier pixel porte le Numéro 0
 
   // n'oubliez pas que le premier pixel porte le Numéro 0
 
   for(int i=0; i<NUMPIXELS; i++) { // Pour chaque pixel...
 
   for(int i=0; i<NUMPIXELS; i++) { // Pour chaque pixel...
 +
 
     // pixels.Color() prends les valeurs RGB de 0,0,0 jusqu'à 255,255,255
 
     // pixels.Color() prends les valeurs RGB de 0,0,0 jusqu'à 255,255,255
     pixels.setPixelColor(i, pixels.Color(b, 50, 255));
+
     pixels.setPixelColor(i, pixels.Color(rouge, vert, bleu));
 
   }
 
   }
 
 
   pixels.show();  // on affiche les pixels
 
   pixels.show();  // on affiche les pixels
  digitalWrite(vib, LOW);
 
 
   delay(T);
 
   delay(T);
 
   }
 
   }
 +
  }
 +
}
 +
 +
void testEEPROM(){ // On test si la mémoire de l'ESP contient déjà des infos d'une configuration précédente
 +
  if(EEPROM.percentUsed()>=0) { // Si il y en a on ne fait rien
 +
    Serial.println("Il y a des infos dans la mémoire");
 +
    Serial.print(EEPROM.percentUsed());
 +
    Serial.println("% de l'espace mémoire flash de l'ESP flash actuellement utilisé.");
 +
    EEPROM.get(0, rouge); Serial.print("Valeur de rouge EEPROM = "); Serial.println(rouge);
 +
    EEPROM.get(4, vert); Serial.print("Valeur de vert EEPROM = "); Serial.println(vert);
 +
    EEPROM.get(8, bleu); Serial.print("Valeur de bleu EEPROM = "); Serial.println(bleu);
 +
  } else {      // Si il n'y en a pas on stocke la couleur pas défaut
 +
    EEPROM.put(0, rouge);
 +
    EEPROM.put(4, vert);
 +
    EEPROM.put(8, bleu);
 +
    boolean ok = EEPROM.commit();
 +
    Serial.println((ok) ? "Commit initialisation couleur OK" : "Commit initialisation couleur raté"); 
 +
  }
 +
}
 +
void choixCouleur(){
 +
  WiFiClient client = serveurPOCL.available(); // On écoute si il y a des connexions sur le site web du POCL (des clients)
 +
 +
  if (client) {                                // Si il y a une nouvelle connexion,
 +
    currentTime = millis();
 +
    previousTime = currentTime;
 +
    Serial.println("Nouveau client connecté");          // print a message out in the serial port
 +
    String currentLine = "";                // créer une chaîne pour contenir les données entrantes du client
 +
    while (client.connected() && currentTime - previousTime <= timeoutTime) {            // Boucle "while", tant que le client est connecté
 +
      currentTime = millis();
 +
      if (client.available()) {            // if there's bytes to read from the client,
 +
        char c = client.read();            // read a byte, then
 +
        Serial.write(c);                    // print it out the serial monitor
 +
        header += c;
 +
        if (c == '\n') {                    // if the byte is a newline character
 +
          // if the current line is blank, you got two newline characters in a row.
 +
          // that's the end of the client HTTP request, so send a response:
 +
          if (currentLine.length() == 0) {
 +
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
 +
            // and a content-type so the client knows what's coming, then a blank line:
 +
            client.println("HTTP/1.1 200 OK");
 +
            client.println("Content-type:text/html");
 +
            client.println("Connection: close");
 +
            client.println();
 +
                 
 +
            // Affiche la page web
 +
            client.println("<!DOCTYPE html><html>");
 +
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
 +
            client.println("<link rel=\"icon\" href=\"data:,\">");
 +
            client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">");
 +
            client.println("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js\"></script>");
 +
            client.println("</head><body><div class=\"container\"><div class=\"row\"><h1>Choisi la couleur de ton POCL</h1></div>");
 +
            client.println("<a class=\"btn btn-primary btn-lg\" href=\"#\" id=\"change_color\" role=\"button\">Change de Couleur</a> ");
 +
            client.println("<input class=\"jscolor {onFineChange:'update(this)'}\" id=\"rgb\"></div>");
 +
            client.println("<script>function update(picker) {document.getElementById('rgb').innerHTML = Math.round(picker.rgb[0]) + ', ' +  Math.round(picker.rgb[1]) + ', ' + Math.round(picker.rgb[2]);");
 +
            client.println("document.getElementById(\"change_color\").href=\"?r\" + Math.round(picker.rgb[0]) + \"g\" +  Math.round(picker.rgb[1]) + \"b\" + Math.round(picker.rgb[2]) + \"&\";}</script></body></html>");
 +
            // The HTTP response ends with another blank line
 +
            client.println();
 +
 +
            // Request sample: /?r201g32b255&
 +
            // Red = 201 | Green = 32 | Blue = 255
 +
            if(header.indexOf("GET /?r") >= 0) {
 +
              pos1 = header.indexOf('r'); // pos1 est la position du caractère r dans la chaine de caractères.
 +
              pos2 = header.indexOf('g'); // idem
 +
              pos3 = header.indexOf('b');
 +
              pos4 = header.indexOf('&');
 +
              redString = header.substring(pos1+1, pos2); // la chaine de caractère juste après pos1 et jusqu'à pos2 est placée dans la variable redString.
 +
              greenString = header.substring(pos2+1, pos3); // ...
 +
              blueString = header.substring(pos3+1, pos4);
 +
              Serial.println(redString.toInt()); // je publie sur le moniteur série
 +
              Serial.println(greenString.toInt());
 +
              Serial.println(blueString.toInt());
 +
              rouge = redString.toInt(); // je transforme la chaine de caractère en nombre entier que je met dans la variable rouge
 +
              vert = greenString.toInt();
 +
              bleu = blueString.toInt();
 +
              // Je stocke la configuration dans la mémoire du D1 mini
 +
              EEPROM.put(0, rouge);
 +
              EEPROM.put(4, vert);
 +
              EEPROM.put(8, bleu);
 +
              boolean ok1 = EEPROM.commit();
 +
              Serial.println((ok1) ? "Commit couleur OK" : "Commit couleur raté");
 +
            }
 +
            // On sort ("break") de la boucle "while"
 +
            break;
 +
          } else { // if you got a newline, then clear currentLine
 +
            currentLine = "";
 +
          }
 +
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
 +
          currentLine += c;      // add it to the end of the currentLine
 +
        }
 +
      }
 +
    }
 +
    // Clear the header variable
 +
    header = "";
 +
    fade();
 +
    // Close the connection
 +
    client.stop();
 +
    Serial.println("Client disconnected.");
 +
    Serial.println("");
 
   }
 
   }
 
}
 
}
  
 
void setup() {
 
void setup() {
   Serial.begin(115200);
+
   Serial.begin(115200); // Ouverture de communication série
 +
 
 +
  uint32_t chipid=ESP.getChipId();
 +
  snprintf(nomPOCL,25,"MouMouNa - %08X",chipid);
 +
  Serial.print("Je suis le MouMouNa ");
 +
  Serial.println(nomPOCL);
 +
 
 +
  EEPROM.begin(16);
 +
  testEEPROM();
 +
 
 
   WiFi.mode(WIFI_STA); // la carte D1 mini est mise en mode STATION
 
   WiFi.mode(WIFI_STA); // la carte D1 mini est mise en mode STATION
 
   WiFiManager MonReseauWifi; // on crée l'objet "MonReseauWifi"
 
   WiFiManager MonReseauWifi; // on crée l'objet "MonReseauWifi"
 
    
 
    
 
   bool res;
 
   bool res;
   res = MonReseauWifi.autoConnect("Wifi POCL Pokou"); // le POCL diffuse un réseau wifi en accès libre nommé "Wifi POCL Pokou"
+
   res = MonReseauWifi.autoConnect("MouMouNa"); // le POCL diffuse un réseau wifi en accès libre nommé "MouMouNa"
 
      
 
      
 
   if(!res) {
 
   if(!res) {
  Serial.println("La connexion n'a pas fonctionnée...");
+
    Serial.println("La connexion n'a pas fonctionnée...");
  }  
+
    }  
 
   else {
 
   else {
  Serial.println("Vous êtes connecté au Wifi... :-)");
+
    Serial.println("Vous êtes connecté au Wifi... :-)");
  }  
+
 
 
+
    // Print local IP address and start web server
 +
    Serial.println("");
 +
    Serial.println("WiFi connected.");
 +
    Serial.println("IP address : ");
 +
    Serial.println(WiFi.localIP());
 +
    serveurPOCL.begin(); //démarrage du serveur Web du POCL
 +
    }
 +
 
 
   pixels.begin(); //on initialise le ruban "pixels"
 
   pixels.begin(); //on initialise le ruban "pixels"
 
   pinMode(brocheBouton,INPUT_PULLUP);
 
   pinMode(brocheBouton,INPUT_PULLUP);
 
+
  pinMode(PIN,OUTPUT);
 +
 
 
   pinMode(LED_BUILTIN, OUTPUT);
 
   pinMode(LED_BUILTIN, OUTPUT);
 
   digitalWrite(LED_BUILTIN, HIGH);
 
   digitalWrite(LED_BUILTIN, HIGH);
   pinMode(vib, OUTPUT);
+
    
  digitalWrite(vib, LOW);
+
   // préparation de la connexion au serveur MQTT
 
+
   clientMQTT.begin(BROKER_IP, 1883, net); // (IP, port, Client Wifi défini plus haut)
   // on se connecte au client
+
   clientMQTT.onMessage(messageReceived); // Si on reçoit un message MQTT, la fonction "messageReceived" est appelée.
   client.begin(BROKER_IP, 1883, net); // (IP, port, Client Wfi défini plus haut)
 
   client.onMessage(messageReceived);
 
  
   connect();
+
   connect(); // On se connecte
 +
  Serial.println("Programme MouMouNa V1 en date du 24 mars 2025");
 
}
 
}
  
 
void loop() {
 
void loop() {
   pixels.clear(); // Set all pixel colors to 'off'
+
   pixels.clear(); // éteint tout les pixels
   pixels.show();
+
   pixels.show(); // affiches pixels
   digitalWrite(vib, LOW);
+
    
 
+
   clientMQTT.loop();
   client.loop();
+
   delay(10);  // <- fixes some issues with WiFi stability
   delay(100);  // <- fixes some issues with WiFi stability
 
 
 
  
   if (!client.connected()) {
+
   if (!clientMQTT.connected()) {
 +
    Serial.print("MouMouNa ");
 +
    Serial.print(nomPOCL);
 +
    Serial.println(" est déconnecté du serveur MQTT"); 
 
     connect();
 
     connect();
 
   }
 
   }
  
   // publish a message roughly every second.
+
   // Si on appuie sur le bouton, on envoie un messagge MQTT "calin", sur le topic "/mou"
 
   if ( digitalRead(brocheBouton) == LOW ){
 
   if ( digitalRead(brocheBouton) == LOW ){
 
   Serial.println("Appuis Bouton");  
 
   Serial.println("Appuis Bouton");  
   client.publish("/mou", "calin");
+
   clientMQTT.publish("/mou", "calin");
   delay(250);
+
   delay(250); // Filtre anti-rebond du bouton
 
   }
 
   }
 +
 +
  choixCouleur(); // appel de la fonction qui génère la page web de configuration de la couler du POCL
 
}
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  

Version du 24 mars 2025 à 19:38

LOGO MOUMOUNA copie.jpg

résumé du projet

MOUMOUNA - dérivé du mot câliner "moumounan" en breton - est un objet interactif distributeur de câlins à distance. A l'échelle de notre prototype celui-ci peut être déployé dans l'espace familial ou à taille humaine disposé dans l'espace public.

Le principe : Enlacer cet objet textile afin de faire baisser son anxiété ou trouver du réconfort. La pression contre son corps active Moumouna qui émet une douce vibration et s'illumine. Cet étreinte envoie un signal au deuxième "moumouna" disposé dans un autre espace ou une autre ville, qui s'illumine en attendant un câlin en réponse. Les vibrations annoncent que deux personnes s'enlacent par Moumouna interposé.

Un QR code est imprimé sur les deux objets qui vous renvoie vers un bande sonore (bruits de vagues) à télécharger pour renforcer l'expérience du câlin.

Action technique.jpg Moumouna Distributeur de câlins.png MOUMOUNA ACTIVE.jpgNotice moumouna.jpg

membres du projet

Equipe au travail.jpg Equipe.jpg


Aude Mouillot - Catherine Huve - Mélissa Rosingana

Bibliographie et webographie sur le projet

Mettre ici des exemples trouvés sur web de projets qui ressemblent et des technologies qui s'en rapprochent ou qui servent d'inspiration.

  1. calinothérapie

https://www.24heures.ch/les-bienfaits-de-la-calinotherapie-expliques-par-une-experte-803631900339

pistes explorée, abandonnées ou fertiles

CROQUIS / PREMIERES IDEES Croquis 1 moumounan.jpg Idée 1 moumounan.jpg Moumounan projet calin.jpg Proto-moumounan-esquisse.jpg


Inspiration Oeuvre de Catherine Huve " LE GRAND HUG " textiles, mixtes - Dimensions: 40x70cm, 2024

 LE GRAND HUG Catherine Huve.jpg

prototype qu'on souhaite réaliser

PROTOTYPE EN MOUSSE DES DEUX MOUMOUNA

  Prototype moumounan mousse.jpgPrototype en mousse moumounan.jpg

PROTOTYPE TISSUS

 Coussin tissus proto moumounan.jpg

COUTURE DU PROTOTYPE FINAL

 Catherine couture coussin 2.jpg  Catherine couture main coussin.jpg Aude couture housse.jpg Aude couture housse 2.jpg 

REMPLISSAGE AVEC COPEAUX DE BOIS ET COTON

 Cath remplissage moumouna.jpg Copeaux bois.jpg Remplissage moumouna.jpg

COLORATION DU TISSUS Premier proto tissus moumounan.jpg Peinture bombe.jpg Couleur bombe.jpg

BOITE NUMERIQUE

 Boite numerique.jpg Boite numerique 2.jpg  Bande LED Programmation boite moumouna.jpg Vibreur Vibreur moumouna.jpg  
 Programmation.jpg En action.jpg

ASSEMBLAGE DE NOS PROTOTYPES

Decoupe prototype.jpg  Proto details.jpg

PROTOTYPE FINAL

MOUMOUNA-rose.jpg  MOUMOUNA ACTIVE.jpg  Moumouna2.jpg  Calin moumouna.jpg Calindemoumouna.jpg
  Logo moumouna serigraphie.jpg

code

  1  
  2 /////////////////////////////
  3 //      Moumouna      //
  4 /////////////////////////////
  5 /*
  6  * Un projet imaginé et réalisé au Hackathon Passerelle.Infini organisé avec les petits débrouillards au centre d'art Passerelle à Brest les 20 et 21 mars 2025.
  7  * moumouna : https://wiki.lesfabriquesduponant.net/index.php?title=Passerelle.Infini_2025_:_MOUMOUNAN
  8  * 
  9  * Ce programme s'apuie sur le programme POCL Poke (imaginé et réalisé au Hackathon POCL à l'édulab Rennes 2 les 9 et 10 décembre 2021).
 10  * POCL Poke : https://wiki.lesfabriquesduponant.net/index.php?title=POCL_:_Poke
 11  * 
 12  * Configurez le logiciel Arduino pour gérer la carte D1 mini (ESP8266).
 13  * Intégrer les biobliothèues requises par le projet :
 14  ** #include <MQTT.h> -> pour gérer le protocole de communication, c'est la bibliothèque MQTT de Joël Gähwiler : https://github.com/256dpi/arduino-mqtt
 15  ** #include <Adafruit_NeoPixel.h> -> pour gérer les rubans de led
 16  ** #include <WiFiManager.h> -> Bibliothèque WiFiManager pour configurer automatiquement le réseau wifi et le mot de passe.
 17  * 
 18  *                                   BROCHAGE                            
 19                                 _________________                        
 20                                /     D1 mini     \                       
 21                            -  |[ ]RST        TX[ ]| -                    
 22                            -  |[ ]A0  -GPIO  RX[ ]| -                    
 23                               |[ ]D0-16    5-D1[ ]| -                    
 24                               |[ ]D5-14    4-D2[ ]| -                    
 25                     Bouton -  |[X]D6-12    0-D3[X]| - ruban de leds             
 26                            -  |[ ]D7-13    2-D4[ ]| LED_BUILTIN          
 27                            -  |[ ]D8-15     GND[X]| - GND (Boutons, ruban de leds)             
 28                            -  |[ ]3V3 .      5V[X]| - ruban de Led        
 29                               |       +---+       |                     
 30                               |_______|USB|_______|                      
 31 
 32 Matériel :
 33 - des fils dupont.
 34 - un ruban de led RGB WS28B12
 35 - D1 mini (Wemos, LOLIN,...)
 36 - bouton poussoir
 37 - une alimentation 5V
 38 */
 39 /*
 40  * Un travail d'équipe de :
 41  * Alma Oskouei
 42  * Gaëlle Bescond
 43  * Tony Vanpoucke
 44  * Wing-Anh Luy
 45  * Antony Le Goïc-Auffret
 46    ___
 47  / ___ \
 48 |_|   | |
 49      /_/ 
 50      _   ___   _ 
 51     |_| |___|_| |_
 52          ___|_   _|
 53         |___| |_|
 54 Les petits Débrouillards - mars 2025 CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
 55 // Programme nourri de https://randomnerdtutorials.com/esp32-esp8266-rgb-led-strip-web-server/
 56 // Programme inspiré de celui par Joël Gähwiler
 57 // https://github.com/256dpi/arduino-mqtt
 58 
 59 Améliorations :
 60 reboot en cas de déconnexion MQTT
 61 
 62 */
 63 #include <ESP8266WiFi.h>
 64 #include <MQTT.h> // Bibliothèque MQTT par Joël Gaehwiler
 65 #include <Adafruit_NeoPixel.h> // Bibliothèque NeoPixel d'Adafruit
 66 #include <WiFiManager.h> // Bibliothèque WiFiManager pour configurer automatiquement le réseau wifi et le mot de passe.
 67 #include <ESP_EEPROM.h>
 68 
 69 WiFiClient net; //on crée l'objet WiFiClient "Net"
 70 WiFiServer serveurPOCL(80);
 71 MQTTClient clientMQTT;
 72 #define BROKER_IP "debrouillards.ddns.net" //IP du serveur sur lequel est installé le Broker MQTT
 73 
 74 unsigned long lastMillis = 0;
 75 
 76 char nomPOCL[25];         // variable de stockage du nom unique du POCL
 77 
 78 
 79 //==============Vibreur======================
 80 const int vib = D2; // broche vibreur
 81 //=============Eléments pour le ruban de led et le bouton===============
 82 
 83 // Broche de connexion du ruban de LED
 84 #define PIN D3 // Il faudra changer en D2 (broche plus adpatée).
 85 
 86 int brocheBouton = 12; //GPIO de la broche D6
 87 int rouge = 0;
 88 int bleu = 255;
 89 int vert = 0;
 90 
 91 // Nombre de Led RDGB dans votre ruban
 92 #define NUMPIXELS 6 
 93 
 94 // on configurer un riban nommé "pixels"
 95 Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
 96 
 97 #define T 1 // temps pour gérer le fade du ruban
 98 //==============================================================
 99 
100 //===============Eléments pour le choix de la couleur du Ruban===============
101 // Pour décoder les valeurs de HTTP GET
102 String redString = "0";
103 String greenString = "0";
104 String blueString = "0";
105 int pos1 = 0;
106 int pos2 = 0;
107 int pos3 = 0;
108 int pos4 = 0;
109 
110 // Variable to store the HTTP req  uest
111 String header;
112 
113 // Setting PWM bit resolution
114 // const int resolution = 256;
115 
116 // Current time
117 unsigned long currentTime = millis();
118 // Previous time
119 unsigned long previousTime = 0; 
120 // Define timeout time in milliseconds (example: 2000ms = 2s)
121 const long timeoutTime = 2000;
122 
123 //==============================================================================
124 void connect() {
125   Serial.print("Vérification de la connexion Wifi...");
126   while (WiFi.status() != WL_CONNECTED) {
127     Serial.print(".");
128     delay(1000);
129   }
130   Serial.println("\nPOCL Connecté au Wifi :-) ");
131   Serial.print("\nconnexion au serveur MQTT en cours ");
132   //connection au serveur MQTT : identifiant, User, mot de passe
133   while (!clientMQTT.connect(nomPOCL, "poclpokou", "pokou")) {
134     Serial.println(".");
135     delay(300);
136   }
137 
138   Serial.println("\nconnecté à MQTT !");
139 
140 // on s'abonne au sujet (topic) "/mou" 
141   clientMQTT.subscribe("/mou"); // Attention à la casse !! La casse c'est maj ou minuscule
142   Serial.println("Abonné à /mou");
143   // client.unsubscribe("/mou");// Pour se désinscrire
144 }
145 
146 void messageReceived(String &topic, String &payload) {
147   digitalWrite(LED_BUILTIN, HIGH);
148   fade();
149   Serial.println("incoming: " + topic + " - " + payload);
150   if (payload == "calin"){
151     Serial.println("clic !");
152     digitalWrite(LED_BUILTIN, LOW);
153     delay(100);
154     digitalWrite(LED_BUILTIN, HIGH);
155   }
156 }
157 
158 void fade() {
159   EEPROM.get(0, rouge); Serial.print("Valeur de rouge EEPROM = "); Serial.println(rouge);
160   EEPROM.get(4, vert); Serial.print("Valeur de vert EEPROM = "); Serial.println(vert);
161   EEPROM.get(8, bleu); Serial.print("Valeur de bleu EEPROM = "); Serial.println(bleu);
162   
163   for (int sig=0; sig<3; sig++){
164   for (int b=0; b<255; b++){
165   pixels.setBrightness(b);
166   
167   for(int i=0; i<NUMPIXELS; i++) {
168     pixels.setPixelColor(i, pixels.Color(rouge, vert, bleu));
169   }
170   pixels.show();   // On allume les rubans
171   delay(T);
172   }
173 
174   for (int b=255; b>1; b--){ //boucle de gestion de la brillance
175   pixels.setBrightness(b);
176   
177   // n'oubliez pas que le premier pixel porte le Numéro 0
178   for(int i=0; i<NUMPIXELS; i++) { // Pour chaque pixel...
179 
180     // pixels.Color() prends les valeurs RGB de 0,0,0 jusqu'à 255,255,255
181     pixels.setPixelColor(i, pixels.Color(rouge, vert, bleu));
182   }
183   pixels.show();   // on affiche les pixels
184   delay(T);
185   }
186   }
187 }
188 
189 void testEEPROM(){ // On test si la mémoire de l'ESP contient déjà des infos d'une configuration précédente
190    if(EEPROM.percentUsed()>=0) { // Si il y en a on ne fait rien
191     Serial.println("Il y a des infos dans la mémoire");
192     Serial.print(EEPROM.percentUsed());
193     Serial.println("% de l'espace mémoire flash de l'ESP flash actuellement utilisé.");
194     EEPROM.get(0, rouge); Serial.print("Valeur de rouge EEPROM = "); Serial.println(rouge);
195     EEPROM.get(4, vert); Serial.print("Valeur de vert EEPROM = "); Serial.println(vert);
196     EEPROM.get(8, bleu); Serial.print("Valeur de bleu EEPROM = "); Serial.println(bleu);
197   } else {       // Si il n'y en a pas on stocke la couleur pas défaut
198     EEPROM.put(0, rouge);
199     EEPROM.put(4, vert);
200     EEPROM.put(8, bleu);
201     boolean ok = EEPROM.commit();
202     Serial.println((ok) ? "Commit initialisation couleur OK" : "Commit initialisation couleur raté");  
203   }
204 }
205 void choixCouleur(){
206   WiFiClient client = serveurPOCL.available(); // On écoute si il y a des connexions sur le site web du POCL (des clients)
207 
208   if (client) {                                // Si il y a une nouvelle connexion,
209     currentTime = millis();
210     previousTime = currentTime;
211     Serial.println("Nouveau client connecté");          // print a message out in the serial port
212     String currentLine = "";                // créer une chaîne pour contenir les données entrantes du client
213     while (client.connected() && currentTime - previousTime <= timeoutTime) {            // Boucle "while", tant que le client est connecté
214       currentTime = millis();
215       if (client.available()) {             // if there's bytes to read from the client,
216         char c = client.read();             // read a byte, then
217         Serial.write(c);                    // print it out the serial monitor
218         header += c;
219         if (c == '\n') {                    // if the byte is a newline character
220           // if the current line is blank, you got two newline characters in a row.
221           // that's the end of the client HTTP request, so send a response:
222           if (currentLine.length() == 0) {
223             // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
224             // and a content-type so the client knows what's coming, then a blank line:
225             client.println("HTTP/1.1 200 OK");
226             client.println("Content-type:text/html");
227             client.println("Connection: close");
228             client.println();
229                    
230             // Affiche la page web
231             client.println("<!DOCTYPE html><html>");
232             client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
233             client.println("<link rel=\"icon\" href=\"data:,\">");
234             client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">");
235             client.println("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js\"></script>");
236             client.println("</head><body><div class=\"container\"><div class=\"row\"><h1>Choisi la couleur de ton POCL</h1></div>");
237             client.println("<a class=\"btn btn-primary btn-lg\" href=\"#\" id=\"change_color\" role=\"button\">Change de Couleur</a> ");
238             client.println("<input class=\"jscolor {onFineChange:'update(this)'}\" id=\"rgb\"></div>");
239             client.println("<script>function update(picker) {document.getElementById('rgb').innerHTML = Math.round(picker.rgb[0]) + ', ' +  Math.round(picker.rgb[1]) + ', ' + Math.round(picker.rgb[2]);");
240             client.println("document.getElementById(\"change_color\").href=\"?r\" + Math.round(picker.rgb[0]) + \"g\" +  Math.round(picker.rgb[1]) + \"b\" + Math.round(picker.rgb[2]) + \"&\";}</script></body></html>");
241             // The HTTP response ends with another blank line
242             client.println();
243 
244             // Request sample: /?r201g32b255&
245             // Red = 201 | Green = 32 | Blue = 255
246             if(header.indexOf("GET /?r") >= 0) {
247               pos1 = header.indexOf('r'); // pos1 est la position du caractère r dans la chaine de caractères.
248               pos2 = header.indexOf('g'); // idem
249               pos3 = header.indexOf('b');
250               pos4 = header.indexOf('&');
251               redString = header.substring(pos1+1, pos2); // la chaine de caractère juste après pos1 et jusqu'à pos2 est placée dans la variable redString.
252               greenString = header.substring(pos2+1, pos3); // ...
253               blueString = header.substring(pos3+1, pos4);
254               Serial.println(redString.toInt()); // je publie sur le moniteur série
255               Serial.println(greenString.toInt());
256               Serial.println(blueString.toInt());
257               rouge = redString.toInt(); // je transforme la chaine de caractère en nombre entier que je met dans la variable rouge
258               vert = greenString.toInt();
259               bleu = blueString.toInt();
260               // Je stocke la configuration dans la mémoire du D1 mini
261               EEPROM.put(0, rouge);
262               EEPROM.put(4, vert);
263               EEPROM.put(8, bleu);
264               boolean ok1 = EEPROM.commit();
265               Serial.println((ok1) ? "Commit couleur OK" : "Commit couleur raté");
266             }
267             // On sort ("break") de la boucle "while"
268             break;
269           } else { // if you got a newline, then clear currentLine
270             currentLine = "";
271           }
272         } else if (c != '\r') {  // if you got anything else but a carriage return character,
273           currentLine += c;      // add it to the end of the currentLine
274         }
275       }
276     }
277     // Clear the header variable
278     header = "";
279      fade();
280     // Close the connection
281     client.stop();
282     Serial.println("Client disconnected.");
283     Serial.println("");
284   }
285 }
286 
287 void setup() {
288   Serial.begin(115200); // Ouverture de communication série
289 
290   uint32_t chipid=ESP.getChipId();
291   snprintf(nomPOCL,25,"MouMouNa - %08X",chipid);
292   Serial.print("Je suis le MouMouNa "); 
293   Serial.println(nomPOCL);
294   
295   EEPROM.begin(16);
296   testEEPROM(); 
297   
298   WiFi.mode(WIFI_STA); // la carte D1 mini est mise en mode STATION
299   WiFiManager MonReseauWifi; // on crée l'objet "MonReseauWifi"
300    
301   bool res;
302   res = MonReseauWifi.autoConnect("MouMouNa"); // le POCL diffuse un réseau wifi en accès libre nommé "MouMouNa"
303      
304   if(!res) {
305     Serial.println("La connexion n'a pas fonctionnée...");
306     } 
307   else {
308     Serial.println("Vous êtes connecté au Wifi... :-)");
309   
310     // Print local IP address and start web server
311     Serial.println("");
312     Serial.println("WiFi connected.");
313     Serial.println("IP address : ");
314     Serial.println(WiFi.localIP());
315     serveurPOCL.begin(); //démarrage du serveur Web du POCL
316     }
317   
318   pixels.begin(); //on initialise le ruban "pixels"
319   pinMode(brocheBouton,INPUT_PULLUP);
320   pinMode(PIN,OUTPUT);
321   
322   pinMode(LED_BUILTIN, OUTPUT);
323   digitalWrite(LED_BUILTIN, HIGH);
324   
325   // préparation de la connexion au serveur MQTT
326   clientMQTT.begin(BROKER_IP, 1883, net); // (IP, port, Client Wifi défini plus haut)
327   clientMQTT.onMessage(messageReceived); // Si on reçoit un message MQTT, la fonction "messageReceived" est appelée.
328 
329   connect(); // On se connecte
330   Serial.println("Programme MouMouNa V1 en date du 24 mars 2025");
331 }
332 
333 void loop() {
334   pixels.clear(); // éteint tout les pixels
335   pixels.show(); // affiches pixels
336   
337   clientMQTT.loop();
338   delay(10);  // <- fixes some issues with WiFi stability
339 
340   if (!clientMQTT.connected()) {
341     Serial.print("MouMouNa ");
342     Serial.print(nomPOCL);
343     Serial.println(" est déconnecté du serveur MQTT");   
344     connect();
345   }
346 
347   // Si on appuie sur le bouton, on envoie un messagge MQTT "calin", sur le topic "/mou"
348   if ( digitalRead(brocheBouton) == LOW ){
349   Serial.println("Appuis Bouton"); 
350   clientMQTT.publish("/mou", "calin");
351   delay(250); // Filtre anti-rebond du bouton
352   }
353 
354   choixCouleur(); // appel de la fonction qui génère la page web de configuration de la couler du POCL
355 }

ne pas toucher en dessous de ce paragraphe