Nounou ESP pour chats

par dolivier

Ce document est en cours de rédaction. Il est donc sujet à de fortes modifications.

Les vacances d’été arrivent (2016) arrivent et ma plus jeune fille en 4ème grace à son professeur de technologie s’intéresse à tout ce qui tourne autour des arduinos. J’ai donc cherché une idée qui soit suffisament ludique et utile à la maison et qui permette une progression dans les concepts. Il m’a semblé que réaliser un distributeur de croquettes et d’eau automatique pour nos chats pouvait être une bonne idée. Ce billet va donc être la description de notre progression. En espérant que nos chats ne mourront pas de faim à cause de nos incompétences.

En première analyse il faut mettre en place :

  • Une balance ;
  • Un affichage ;
  • Commander un moteur asservi à une balance ;
  • Commander une électrovanne asservie à une balance ;
  • Réaliser une installation pour contenir les croquettes et l’eau ;
  • Détection des niveaux des réservoirs ;
  • Connecter le tout au réseau pour pouvoir envoyer un message lorsque les réservoirs d’eau ou de croquettes sont vides.

Balance première version

Nous allons commencer par réaliser une balance pour peser nos chats <;). Non plutôt pour peser la gamelle d’eau et la gamelle de croquettes afin de pouvoir savoir quand pouvoir les remplir. Cela permettra également servir de balance de cuisine si cela fonctionne correctement.

Matériel

Les premiers tests effectués (Version 0) avec ma fille ont été réalisé avec un arduino Uno (), puis avec un ESP8266 (Version 1) pour un montage un peu plus sophistiqué. Vous trouverez donc ci-dessous la description de chacune de ces versions.

Version 0

  • Un capteur de force. C’est une petite barre d’aluminium percée d’un double trou, sur laquelle est collée une jauge de contrainte ;
  • Un convertisseur analogique/numérique à 24 bits HX711 ;
  • Un arduino Uno.

Capteur de force HX7111

Version 1

  • Un capteur de force.
  • Un convertisseur analogique/numérique à 24 bits HX711 ;
  • Un convertisseur USB/série FTDI ;
  • Une alimentation externe pour les tests ;
  • Un ESP8266.

Montages

Tout d’abord il faut réaliser la balance. Dans un premier temps nous avons utilisé du plexiglas, mais je pense que l’on réalisera les plateaux en aluminium pour une réalisation moins souple et plus résistante.

Capteur et plateau en plexiglas
Balance avec le capteur de force. On remarquera les écrous entre les plaques et le capteur pour permettre la flexion.

Version 0

Il existe plusieurs cartes HX711 (1 rouge et 1 verte) dont les broches ne sont pas cablées de la même façon. Au niveau de l’arduino cela nous donne la correspondance suivante :

Arduino HX711 vert HX711 rouge
GND GND GND
A2 DT DO/RX
A3 SCK CK/TX
+5v Vcc Vcc

Connection entre le capteur de force et HX711

Capteur HX711
Cable rouge Broche E+
Cable noir Broche E-
Cable vert Broche A-
Cable blanc Broche A+
Schéma de montage
Schéma de montage

Version 1

Pour cette version, on utilise donc un ESP8266. Si vous ne l’avez pas déjà installé, vous trouverez des informations ici. Le cablage entre l’ESP8266 et l’HX711 est le suivant :

ESP HX711
3.3V VCC
GPIO 0 SCK
GPIO 2 DT
GND GND
Schéma de montage
Schéma de montage

Attention pour pouvoir téléverser votre programme, il faut que la broche GPIO 0 soit à la masse GND lorsque vous mettez sous tension votre ESP8266. C’est le role du fil blanc que vous connectez alors à la masse. Vous pouvez ensuite le repositionner.

Codes

Vous devez récupérer une librairie pour HX711 pour commencer. Avec l’IDE ARduino il suffit d’aller dans le gestionnaire de librairie, elle est présente.

Version 0

//
// Mesure de poids à l'aide d'une jauge de contrainte et un circuit hx711
//
// Tarage de la balance, définition de l'échelle
// Mesure de poids
//
// Pas de prise en compte de la dérive, ni de correction lié à la température
//

#include <Q2HX711.h>
#ifdef ESP
  const byte hx711_broche_donnee  = 2;
  const byte hx711_broche_horloge = 0;
#else
  const byte hx711_broche_donnee  = A2;
  const byte hx711_broche_horloge = A3;
#endif

Q2HX711 hx711(hx711_broche_donnee, hx711_broche_horloge);

long Zero = 0;
float Echelle = 1;

//
// On cherche à faire le zéro
//
void tare()
{
  const unsigned int nbfois = 100,
                     attente = 50;
  unsigned int i;
  Serial.println("Tarage de la balance ");
  Serial.println("Merci de ne rien poser dessus");
  while (! hx711.readyToSend());
  for ( i = 0; i < nbfois; i++)
  {
    Zero += hx711.read();
    delay(attente);
  }
  Zero /= nbfois;
}

//
// On calcule l'échelle à partir d'un poids connu
//
void scale()
{
  float grammes;
  Serial.println("Poser un poids connu et donner sa valeur en g");
  while (Serial.available()==0);
  grammes = Serial.readString().toFloat();
  Echelle = (Zero - hx711.read()) / grammes;
  Serial.print("Scale = "); Serial.println(Echelle);
}

void setup() {
  Serial.begin(115200);
  tare();
  scale();
}

void loop() {
  if (hx711.readyToSend())
    Serial.println((Zero - hx711.read()) / Echelle);
  else Serial.println(">>:)");
  delay(500);
}

Version 1

Il vous suffit de rajouter #define ESP avant le #ifdef ESP .

Balance deuxième version

Pour cette version, nous allons utiliser le Wifi de l’ESP8266 et le courtier de message (broker) mosquitto. Vous trouverez plus d’information sur MQTT et mosquitto, ici. Pour installer mosquitto sous ubuntu xenial (16.04) :

 % sudo bash -c 'echo "deb http://ppa.launchpad.net/mosquitto-dev/mosquitto-ppa/ubuntu xenial main" > /etc/apt/sources.list.d/mosquitto-dev-mosquitto-ppa-xenial.list'
 % sudo apt-get update
 % sudo apt-get install mosquitto mosquitto-clients

Le montage est identique à celui déjà réalisé et comme précedmment il faudra mettre la broche GPIO 0 avant la mise sous tension pour téléverser votre programme. Le programme proposé permet de supprimer les sorties dans la console ainsi que la partie montage avec le FTDI.

 /*
   Exemple HX711 ESP8266 MQTT
   avec une publication de la part de l'ESP qui se connecte sur un broker MQQT (local) :
   - Publie sur le fil "balanceOUT" les mesures après avoir reçu l'ordre de peser
   - S'abonne au fil "balanceIN" lorsqu'une info est reçue elle est traitée :
       Cela peut-être une demande de tarage (Tarage) ;
       Une mise à l'échelle (Echelle poidsEng) ;
       Une pesée (Pesage).
 */

 #include <ESP8266WiFi.h>
 #include <PubSubClient.h>
 extern "C" {
 #include <user_interface.h>
 }

 #define DEBUG       // A supprimer pour ne plus avoir de trace dans la console
 #ifdef DEBUG
   #define DEBUG_BEGIN(x)        Serial.begin(x)
   #define DEBUG_PRINT(x)        Serial.print(x)
   #define DEBUG_PRINTLN(x)      Serial.println(x)
 #else
   #define DEBUG_BEGIN(x)
   #define DEBUG_PRINT(x)
   #define DEBUG_PRINTLN(x)
 #endif

 #include <Q2HX711.h>
 const byte hx711_broche_donnee  = 2;  // GPIO 2 de l'ESP
 const byte hx711_broche_horloge = 0;  // GPIO 0 de l'ESP
 Q2HX711 hx711(hx711_broche_donnee, hx711_broche_horloge);
 long Zero = 0;                        // La tare
 float Echelle = 1;


 // Pour identifier l'ESP
 uint8_t MAC_array[6];
 char MAC_char[18];

 // Mettre à jour suivant votre réseau
 const char* SSID = "Le SSID de votre réseau";
 const char* PASSWORD = "Votre mot de passe";
 byte mqtt_serveur[] = {192, 168, 0, 18}; // IP du broker à modifier

 // PORT d'écoute de MQTT (valeur par défaut)
 const unsigned int PORT = 1883;

 WiFiClient espClient;
 PubSubClient client(espClient);
 char Message[150];

 //==============================================================================
 void setup() {
   DEBUG_BEGIN(115200);
   DEBUG_PRINTLN();
   WiFi.macAddress(MAC_array);
   for (int i = 0; i < sizeof(MAC_array); ++i) {
     sprintf(MAC_char, "%s%02x:", MAC_char, MAC_array[i]);
   }
   setup_wifi();
   setup_mqtt();
 }

 void loop() {
   if (!client.connected()) {
     setup_connect();
   }
   delay(2000);
   client.loop();
 }
 //==============================================================================


 //=============================Over the air=====================================

 //------------------------------------------------------------------------------
 // Gestion du Wifi
 //
 void setup_wifi() {
   delay(10);
   // Connexion au Wi-fi
   DEBUG_PRINTLN();
   DEBUG_PRINTLN();
   DEBUG_PRINT("Connexion à : ");
   DEBUG_PRINTLN(SSID);
   WiFi.begin(SSID, PASSWORD);
   DEBUG_PRINT("\n\r \n\rC'est en cours");

   while (WiFi.status() != WL_CONNECTED) {
     delay(500);
     DEBUG_PRINT(".");
   }

   DEBUG_PRINTLN("");
   DEBUG_PRINT("ESP connecté au Wi-fi ");
   DEBUG_PRINTLN(SSID);
   DEBUG_PRINT("Adresse IP : ");
   DEBUG_PRINTLN(WiFi.localIP());
 }
 //------------------------------------------------------------------------------


 //------------------------------------------------------------------------------
 // Gestion de MQTT
 //
 void setup_mqtt()
 {
   client.setServer(mqtt_serveur, PORT);
   client.setCallback(callback);
 }

 void setup_connect() {
   // On tente de se (re)connecter
   while (!client.connected()) {
     DEBUG_PRINTLN("Tentative de connexion MQTT...");
     if (client.connect(MAC_char)) {
       DEBUG_PRINTLN("connecté");
       // Une fois connecté on le fait savoir
       client.publish("balanceOUT", "Connecté au MQTT");
       client.subscribe("balanceIN", 1);
     } else {
       DEBUG_PRINT("echec, rc=");
       DEBUG_PRINTLN(client.state());
       DEBUG_PRINT(" nouvel essai dans 5 secondes");
       delay(5000);
     }
   }
 }

 void callback(char* fil, byte* payload, unsigned int longueur) {
   DEBUG_PRINT("Message arrivé [");
   DEBUG_PRINT(fil);
   DEBUG_PRINT("] ");
   char* message_recu = (char *) malloc(longueur * sizeof(char) + 1);
   memcpy(message_recu, payload, longueur);
   message_recu[longueur] = '\0';
   String m = String(message_recu);
   if (m == "Tarage")
   {
     client.publish("balanceOUT", "Tarage");
     tare();
   } else if (m == "Pese")
   {
     client.publish("balanceOUT", "Pesage");
     pesage();
   }  else if (m.substring(0, 7) == "Echelle")
   {
     client.publish("balanceOUT", "Echelle");
     echelle(m.substring(8));
   }
   DEBUG_PRINTLN();
   DEBUG_PRINT("message = ");
   DEBUG_PRINTLN(message_recu);
   free(message_recu);
 }
 //==============================================================================


 //------------------------------------------------------------------------------
 // Gestion de la balance
 //
 void tare()
 {
   const unsigned int nbfois = 100,
                      attente = 50;
   unsigned int i;

   Zero = 0;
   DEBUG_PRINTLN("Tarage de la balance ");
   DEBUG_PRINTLN("Merci de ne rien poser dessus");
   client.publish("balanceOUT", "Tarage de la balance ");
   client.publish("balanceOUT", "Merci de ne rien poser dessus");
   while (! hx711.readyToSend());
   for ( i = 0; i < nbfois; i++)
   {
     Zero += hx711.read();
     delay(attente);
   }
   Zero /= nbfois;
   client.publish("balanceOUT", "La balance est tarée, moi aussi");
 }

 void pesage()
 {
   if (hx711.readyToSend())
   {
     char message[50];
     char valeur[10];
     float pds = (Zero - hx711.read()) / Echelle;
     DEBUG_PRINT("Pesage = ");
     dtostrf(pds, 5, 0, valeur); // Pour résoudre le pb du %f qui ne fonctionne pas !
     snprintf(message, sizeof(message), "Poids = %s g", valeur);
     DEBUG_PRINTLN(pds);
     client.publish("balanceOUT", message);
   }
   else
   {
     DEBUG_PRINTLN(">>:)");
     client.publish("balanceOUT", ">>:)");
   }
 }

 void echelle(String s)
 {
   DEBUG_PRINTLN("Mise à l'échelle ");
   DEBUG_PRINTLN("Merci poser de poser le poids avant");
   client.publish("balanceOUT", "Mise à l'échelle ");
   client.publish("balanceOUT", "Merci poser de poser le poids avant");
   Echelle = (Zero - hx711.read()) / (float) s.toInt();
 }
 //------------------------------------------------------------------------------

Il faut ensuite lancer le serveur mosquitto sur votre machiche armille dans le cas présent pour ce qui me concerne.

% mosquitto -c /etc/mosquitto/conf.d/mosquitto.conf -d -v
% mosquitto_sub -h armille -t balanceOUT &
mosquitto_sub -h armille -t balanceOUT &

Dans une autre console vous pouvez lancer les commandes :

  • Pour tarer la balance qui doit être à vide. mosquitto_pub -h localhost -t balanceIN -m Tarage
  • Pour mettre à l’échelle les mesures, avec un poids dont on connait la valeur en g (500 par ex.). mosquitto_pub -h localhost -t balanceIN -m "Echelle 500"
  • Pour peser mosquitto_pub -h localhost -t balanceIN -m Pese
% mosquitto_pub -h localhost -t balanceIN -m Tarage
Tarage de la balance
Merci de ne rien poser dessus
La balance est tarée, moi aussi
Merci de ne rien poser dessus
La balance est tarée, moi aussi
% mosquitto_pub -h localhost -t balanceIN -m "Echelle 500"
Mise à l'échelle
Merci poser de poser le poids avant
% mosquitto_pub -h localhost -t balanceIN -m Pese
Pesage
Poids =   500 g

Vous avez maintenant une balance connectée, je vous propose maintenant de l’intégrer à un environnement de domotique openHAB basé sur une architecture REST, on pourrait utiliser aussi Node-red.

Nous contacter

Vous pouvez nous contacter à cette adresse ou utiliser le formulaire ci-dessous.