Projet automate aquarium

Mon projet est de faire un automate pour relever la température, commander le chauffage, commander l'éclairage dans un premier temps puis contrôler le PH et le débit de la pompe de filtrage dans un second temps.
J'ai réalisé cette première partie avec une raspberryPi qui fonctionne. Sauf que mes capteurs de température DS18B20 qui peuvent être au nombre de 1 à 4 prennent chacun 750 ms pour répondre et mon affichage des heures,minutes,secondes n'apprécie pas et zappe la ou les seconde correspondante à cette attente.
Après de très nombreuses recherches j'ai trouvé que la solution la plus simple était d'utiliser une carte Arduino (que j'ai commandé mais pas encore reçu).
Mais là ou je bute c'est comment faire car:
Le soft de la pi est sécurisé au démarrage, il faut lui dire combien de sondes sont branchées et si ce nombre est différent du nombre de numéro relevé il refusera de démarrer en renvoyant l'utilisateur vers les paramétrages. De plus ces sondes sont affectées à un rôle précis d'après leur numéro de série
Soit l'arduino va chercher les numéros de série dans la pi et fait le relevé de température en boucle et le présente à la pi et je ne sais pas comment faire
Soit l'arduino recherche ces numéros de série et les présente à la pi puis fait le relevé de température en boucle et le présente à la pi. Ce qui implique que arduino ait mis ces numéros dans un fichier de la Pi avant que le programme démarre et je ne sais pas comment faire
De plus je n'ai pas vraiment compris comment fonctionnait ce relevé de numéros de série de sondes dont le nombre n'est pas fixe au démarrage.

Que me conseillez vous?

Ce n'est manifestement pas un projet finis.
Je déplace dans la racine du forum francophone

Il n'y a pas forcément de raison que Arduino puisse faire des choses qu'un Raspberry ne peut pas.
Je pense donc que tu n'a pas trouvé les bonnes références.

Après utiliser un Raspberry sera surement plus simple pour toi, même si c'est un peu "overkill".

Si tu pars quand même sur un Arduino, il n'est pas forcément nécessaire d'avoir un Raspberry, mais tu ne décris pas suffisamment ton projet, pour pouvoir te le confirmer.

J'utilise une pi simplement parce qu'elle gère un affichage 1920*1080 et qu'elle dispose d'un clavier et d'une souris qui rendent le paramétrage beaucoup plus convivial. De plus la carte arduino est totalement incapable de supporter un gros soft.
Pour ce qui concerne le déportement de la gestion des capteurs je souhaite le faire pour les raisons suivantes:
Sur la pi le capteur DS18B20 est géré par le kernel et je ne peux pas pas me libérer du fait qu'il attende 750ms pour retourner les résultats alors que sur un micropro ça ne pose aucun problème. Il me faudrait soit modifier le kernel linux, du moins le driver, soit écrire une gestion complète des sondes et ne pas faire appel au kernel. Ce qui n'est pas forcément des plus simples.
Deuxièmement je souhaite ultérieurement gérer un débitmètre et le micropro de la pi ne comporte pas de port qui le permettent d'une façon directe et fiable (j'ai déjà testé).
Je me suis orienté vers arduino pour la gestion des capteurs, du fait que la carte est peu chère et que de nombreux forum la conseille pour cette utilisation

oui, je me doute bien, après chacun vois midi à sa porte :slight_smile:
Si un jour j'arrive à relancer mon mini aquarium, je trouverais plus convivial de passer par mon smartphone ou un browser(à distance) pour configurer le "setup", mais c'est très personnel.

Certes, tu n'a pas la même possibilité sur la taille des programmes pouvant s'exécuter.
Après "gros soft" est très subjectif.

Si c'est vraiment impossible de ne pas avoir une attente de 750ms, as tu essayé de passer par des fonction asynchrone, qui du coup ne bloque pas ton programme principal ?

L'un n'empêche pas l'autre mais je n'en ai pas l'utilité actuellement

Je dis gros par rapport à l'arduino

Ce n'est que désagréable de voir des secondes passer de 1 à 3 sans afficher le 2, il suffit que je supprime l'affichage des secondes et hop problème résolu mais à la retraite je dois devenir plus difficile.
J'ai essayé plusieurs solutions mais même en faisant du multitreading le problème demeure. Je pense que c'est au niveau du kernel que cette attente est gênante.

J'espère trouver des solutions dans le forum. Dans un premier temps si @J-M-L peu répondre à la question concernant les numéros de série des sondes DS18B20 cela me permettrait de commencer dès que je vais recevoir ma carte.

Merci

le RPi me semble inutile, un arduino peut tout gérer

vos DS18B20 sont sur une seule broche (ie partagent une instance oneWire) ou vous avez une broche par capteur (et plusieurs instances oneWire pour la communication) ?

Pour les 750ms ça ce gère bien entendu en asynchrone. la bibliothèque DallasTemperature a une fonction requestTemperatures() qui dit au module d'aller faire la lecture, ensuite le code teste si la lecture est disponible avec isConversionComplete() et si oui va lire la valeur puis relance un requestTemperatures() et si non, passe à la suite.

Ainsi votre code est non bloquant et vous pouvez afficher tranquillement les secondes qui passent

Non clairement, c'était surtout te montrer que dans ma (petite) tête, c'était l'écran qui été inutile.

Ouai, mais là encore, cela n'indique pas quel programme pour toi est trop gros pour un Arduino.
En fait dans ton cas, lors d'un passage à un Arduino unique, ce n'est pas forcément la taille(nombre de ligne de code ou caractére) de ton programme qui posera le plus de problème, mais l'occupation mémoire de l'image à afficher sur ton écran qui sera surement limitant.
Et encore si tu prend un Arduino nouvelle génération ou un ESP32, on peux gérer des écrans déjà imposant.

Surement, mais j'avoue que cela me surprend beaucoup.

Merci je m'étais bloqué sur la librairie onewire, je n'avais pas vu que la librairie DallasTemperature étais aussi complète. Sans la carte c'est vraiment trop abstrait pour moi mais votre réponse va quand même me permettre de préparer.

Non, vous pouvez le penser mais pour ne pas encombrer le forum je ne suis pas rentré dans le détail. Les lignes de code sont dans le détail (sécurisation, sauvegarde, alarmes, warnings, programmation d'éclairage multiples etc..) Il me fallait un affichage suffisamment grand pour afficher 4 sondes températures, le Ph et le débit plus les consignes et les alarmes de températures ainsi que les programmations en cours.

tenez voici un exemple où l'écran affiche

  • la température de 4 sondes (en asynchrone)
  • l'heure qui défile
  • un petit truc qui clignote pour montrer que rien n'est bloqué
le code
#include <Wire.h>
#include <hd44780.h>                        // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h>  // i2c expander i/o class header
#include "RTClib.h"
#include "Sonde.h"

// LE LCD
const uint8_t nbColonnes = 20;
const uint8_t nbLignes = 4;
hd44780_I2Cexp lcd;

byte barre[] = {0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100};
byte coeur[] = {0b00000, 0b01010, 0b11111, 0b11111, 0b01110, 0b00100, 0b00000, 0b00000};
byte skull[] = {0b00000, 0b01110, 0b10101, 0b11011, 0b01110, 0b01110, 0b00000, 0b00000};

// la RTC
RTC_DS1307 rtc;

// Les sondes
Sonde sondes[] = {
  { 6, "S1"},
  { 7, "S2"},
  { 8, "S3"},
  { 9, "S4"},
};
constexpr size_t nombreDeSondes = sizeof sondes / sizeof * sondes;

const byte tailleMaxTxt = 10;
char affichageTemperature[nombreDeSondes][tailleMaxTxt];
char affichageHeure[9];

void afficherTemperatures() {
  // on met à jour les températures
  char tmpTxt[tailleMaxTxt];
  for (byte i = 0; i < nombreDeSondes; i++) {
    dtostrf(sondes[i].temperature(), 1, 1, tmpTxt); // conversion en chaîne de caractères
    if (strcmp(tmpTxt, affichageTemperature[i]) != 0) {
      // le texte a changé on effectue le nouvel affichage
      lcd.setCursor(0, i);
      lcd.print(sondes[i].nom);
      lcd.print(": ");
      lcd.print(tmpTxt);
      lcd.write(0xDF); // ° symbol
      if (strlen(tmpTxt) < strlen(affichageTemperature[i])) {
        // le nouveau texte est plus court que l'ancien, on efface les caractères en trop
        for (byte i = 0; i < strlen(affichageTemperature[i]) - strlen(tmpTxt); i++) lcd.write(' ');
      }
      strcpy(affichageTemperature[i], tmpTxt); // on mémorise ce qui est affiché
    }
  }
}

void afficherHeure() {
  DateTime now = rtc.now();
  char heureTxt[9];
  sprintf(heureTxt, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  if (strcmp(affichageHeure, heureTxt) != 0) {
    // l'heure a changée, on effectue l'affichage
    lcd.setCursor(nbColonnes - 8, 0);
    lcd.print(heureTxt);
    strcpy(affichageHeure, heureTxt); // on mémorise ce qui est affiché
  }
}

void blink() {
  static unsigned long chrono = -500;
  static byte symbole = 0; // le coeur, 1 le crane
  if (millis() - chrono >= 500) {
    lcd.setCursor(nbColonnes - 1, nbLignes - 1); // en bas à droite
    lcd.write(symbole);
    symbole = 1 - symbole; // on passe à l'autre symbole
    chrono = millis();
  }
}

void setup() {
  for (Sonde& s : sondes) s.begin();
  Serial.begin(115200);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }
  int result = lcd.begin(nbColonnes, nbLignes);
  if (result) {
    Serial.print("LCD initialization failed: ");
    Serial.println(result);
    hd44780::fatalError(result);
  }
  lcd.createChar(0, coeur);
  lcd.createChar(1, skull);
  lcd.createChar(2, barre);

  // on dessine la barre de séparation
  for (byte i = 0; i < nbLignes; i++) {
    lcd.setCursor(nbColonnes - 9, i);
    lcd.write(2);
  }

}

void loop() {
  afficherTemperatures();
  afficherHeure();
  blink(); // pour montrer qu'on peut faire autre chose du moment que c'est non bloquant
}

Sonde.h

#ifndef _SONDE_H_
#define _SONDE_H_

#include <OneWire.h>
#include <DallasTemperature.h>

class Sonde {
  public:
    Sonde(const byte pinNumber, const char* nom, const uint32_t periodeMaJ = 100);
    void begin();
    float temperature();

    byte pinNumber;
    const char* nom;
    int consigne;

  private:
    OneWire _oneWire;
    DallasTemperature _capteur;
    float _temperature;
    uint32_t _chrono;
    uint32_t _periodeMaJ;
};

#endif

Sonde.cpp

#include "Sonde.h"

Sonde::Sonde(const byte pinNumber, const char* nom, const uint32_t periodeMaJ)
  : _oneWire(pinNumber), _capteur(&_oneWire) {
  this->pinNumber = pinNumber;
  this->nom = nom;
  consigne = 0;
  _periodeMaJ = periodeMaJ;
  _chrono = -periodeMaJ;
  _temperature = -127.0;
}

void Sonde::begin() {
  _capteur.setResolution(12);
  _capteur.setWaitForConversion(false);
  _capteur.begin();
  _capteur.requestTemperatures();
}

float Sonde::temperature() {
  if (millis() - _chrono >= _periodeMaJ) {
    if (_capteur.isConversionComplete()) {
      _temperature = _capteur.getTempCByIndex(0);
      _capteur.requestTemperatures();
      _chrono = millis(); // Mettre à jour le chrono
    }
  }
  return _temperature;
}

si vous clickez sur une des sondes vous pouvez régler la T°, vous verrez que la mise à jour se fait et que l'heure continue de tourner ou la petite animation continue à se faire en bas à droite

Il n'y a que toi pour mesurer tout ce que tu as besoin,
mais @rollmops67 à montré son projet d'afficheur météo qui me parait pas si éloigné du tien.

Pour en remettre une couche(je suis désolé), ton programme ne semble pas si gros que ça.
Je n'ai pas regardé le programme de @J-M-L mais c'est typiquement un projet qui se prête à une machine à état :face_with_hand_over_mouth:

Ce qui est dommage, c'est d'introduire un Arduino pour utiliser même pas 1% de ses capacités, parce que tu as un soucis très étrange de lecture de tes sondes dans un Raspberry.

tout à fait :innocent: (cf mon tuto éventuellement)

@J-M-L Merci pour ces informations tant pour le site que pour le soft

le soft que j'ai fait 780Ko du moins que l'exécutable auquel je vais ajouter quelques Ko pour la sonde Ph et le débitmètre ainsi que quelques Mo pour la mise en page CSS de l'affichage (qui ne sont pas à proprement parler du soft).
J'ai déjà pratiqué sur des micros atmel 8bits 128k et 32 bits 256 et 512k avec AVRStudio , même si ça date je n'en ai pas oublié les limites.

bon c'est pas pour un UNO sans doute, mais un ESP32 par exemple
(cela dit mon petit bout de code ci dessus c'est moins de 15Ko - donc tout dépend comment c'est codé)

Tu vois grand pour avoir un programme de 700Ko, c'est 10 fois plus que l'IDE Arduino, bon c'est surement une coquille vide :slight_smile:
Tu compte faire une feuille de style de plusieurs Mo :dizzy_face:
Je ne dis pas qu'il n'y a pas de limite surtout sur les 8bits, mais ils ne sont plus vraiment la norme.

Après il y a surement une différence entre tout ce que tu gère et la description succincte de ton projet.
Ce que l'on te donne c'est un avis, si on avait à faire le projet que tu décris.

C'est difficilement comparable pour moi ces 15Ko de programmes se résumes à plutôt une dizaine de lignes si je fais un affichage brut comme celui de l'afficheur.

@terwal
Oui, un arrière plan en 1920*1080 fait déjà au moins 1 Mo mais n'occupe qu'une ligne CSS

Je vais juste donner quelques exemple sur la la température qui génère du code

  • avoir la possibilité de modifier le délai entre chaque mesure de température
  • avoir une température de consigne réglable pour chaque sonde et l'afficher
    (en général une sonde au sol, une sonde dans l'eau dont la température est légèrement différente)
  • avoir des warnings de température haute et basse réglables
    (signalement d'un warning lorsque la température s'écarte de la valeur de consigne en fonction de la valeur de warning choisie)
  • avoir des alarmes de température haute et basse réglables (idem warning)
  • le signalement des warning et alarmes modifient la couleur d'affichage de fond de la consigne
  • avoir une alarme qui s'affiche distinctement et qui doit obligatoirement être acquittée en cas de dépassement répétitif de l'alarme (du dessus)
  • le nombre de dépassement répétitif est réglable. L'acquittement ne désactive pas l'alarme mais la réarme.
  • une fenêtre affiche le fonctionnement on/off du chauffage lié à la sonde (eau ou sol)
  • le chauffage est contrôlé par un cycle hystérésis pour éviter les fonctionnement fugitifs.

Oui, 2 Mo même non ?
Mais 10 lignes de CSS, avec des bordures ou autre, ne prendra pas plus de place en mémoire.

un ESP est justement affublé entre 2 et 4 Mo.
Par contre il faudra faire autrement qu'un rendu HTML.

je serai curieux de voir ces 10 lignes qui font ce que fait mon code (avec gestion asynchrone de l'affichage des températures sans clignotement de l'écran, gestion de l'affichage de l'heure en temps réel et du petit heart-beat en bas à droite)

J'envoie une requête au kernel et il me retourne le scratchpad complet 750 ms plus tard soit 3 lignes
lire sonde,
si (reponse),
variable=scratchpad

J'aurais peut être cherché plus ou supprimé l'affichage des secondes si je n'avais pas vu que pour le débitmètre d'eau c'était aussi problématique et que tous les post des forums finissent en conseillant d'utiliser une arduino. Alors quitte à utiliser une arduino autant qu'elle gère tous les capteurs en temps réel et que la Raspberrypi gère l'IHM et l'affichage

Comme vous l’avez vu mon code est asynchrone - ce n’est pas similaire