Contact sec sans fil sur batterie

Bonjour à tous,

Je suis nouveau dans l’univers Jeedom depuis 2 semaines et je suis déjà franchement emballé par les possibilités !
Par contre je suis confronté à un problème :

Je cherche à domotiser des volets roulants Profalux. Ils sont pilotés en radio mais le code est propriétaire donc visiblement c’est à oublier…
Cependant sur les boitiers radio qui sont fixés au mur, Profalux à prévu 3 pins qui une fois reliée à une 4em pin de masse permettent une commande externe. (Monté, descente, stop).
(Source : Domotiser des volets non domotisables - C'est possible ! - La Domotique de Sarakha63)
Ces boitiers sont autonomes et fonctionne avec une pile 3V.
Donc dans l’idéal j’aimerais trouver un « mini module » auto alimenté avec une pile 3V par exemple. Et malgré mes recherches je n’ai trouvé aucun produit existant et peu de problématique similaires… (étrange !)

J’ai pensé à deux solutions :

1/ Je suis très content de mon installation zigbee (via pizigate et plugin zigate)
et des capteurs Xiaomi (température, bouton, relai etc). Je pensais utiliser un relais Reed qui a ma connaissance est le contact sec le moins gourmand en énergie. En détournant la partie zigbee d’une prise connecté par exemple ?
Mais c’est très limité, j’aurai une sortie maxi j’imagine… (a condition que ça soit faisable de modifier l’alimentation également)

2/Toujours avec du Reed et du zigbee (pour la faible consommation et alimentation sur pile bouton 3V) : acheter un module zigbee
et faire mon montage perso, mais comment faire pour l’intégrer dans Jeedom ?
(E18-MS1-PCB Zigbee Module émetteur récepteur sans fil Zigbee IO CC2530 E18 MS1 PCB Ghz 2.4 mW, antenne PCB IoT uhf, réseau maillé, Module émetteur récepteur, 2.5 | AliExpress)

Bref il me manque des éléments dans les deux solutions pour être sur que ça puisse être réalisable. Si vous avez des idées, des pistes, même une solution à partir de zéro, n’hésitez pas!
Je n’ai pas un gros niveau d’électronique, ni de programmation mais ça ne me fait pas spécialement peur d’y passer un peu de temps.

Merci d’avance pour ces échanges ! :slight_smile:

EDIT
'**** SOLUTION '***
Grand merci à @PanoLyon qui a répondu à ma problématique en me proposant l’ESP32 alimenté par batterie ainsi que pour ces explications en programmation !
Depuis j’ai ajouté quelques options aux codes, étant donné que j’ai trouvé peu d’infos dans mes recherches je vais essayer de faire un résumer pour le(s) suivant(s) :

Depuis Jeedom, (plugin MQTT) je déclenche des ordres à travers des topics qui seront interprétés par l’ESP32. Il peut ainsi exécuter les actions associées aux différents ordres. Dans mon cas actionner des micro-relais (SIP-1A03) pour relier les pins de mes télécommandes de volets (exemple ici)
Dès que l’action est effectuée par L’ESP32 il publie un retour d’état pour confirmé à Jeedom que l’ordre à été reçu.
Le but était d’avoir quelque chose de sans fil, compact et autonome pour être implanté près des boîtiers muraux. Pour avoir une bonne autonomie l’ESP32 rentre en mode DeepSleep, lors de son réveil il vérifie si un ordre est en attente, l’exécute le cas échéant puis repasse en mode sommeil. L’autonomie est donc en effet intimement lié au temps de réponse désiré…
Pour palier en parti à ce problème je synchronise l’horloge interne de l’ESP32 avec un serveur NTP. Cela me permet d’ajuster le temps de sommeil en fonction des moments de la journée : 25 secondes pendant les périodes d’utilisation des volets (matin/soir) et 1h en pleine après-midi par exemple. Un fois la syntonisation du temps effectué je le rentre dans l’horloge interne cela me permet d’être à l’heure lors du réveil de l’ESP → pas de besoin de resynchroniser avec le serveur à chaque fois. Ça évite de surcharger les serveurs NTP et ça augmente mon autonomie. D’ailleurs le code permet également la mesure et l’envoi du niveau de batterie à travers un topic MQTT. (en utilisant une pin dédié du lolin D32)

En fouillant sur le net j’ai trouvé plusieurs exemples de code et de documentations de ces fonctions. Mais à chaque fois individuellement. Il ne m’a pas été facile de faire coordonner toutes ces fonctions → Voici donc mon code qui je l’espère pourra servir de bonne base aux prochains rencontrant cette problématique ! :slight_smile:

#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <esp_wifi.h>
#include <esp_bt.h>
#include <time.h>
#include <ezTime.h>
#include <sys/time.h>

// Replace the next variables with your SSID/Password combination
const char* ssid = "******";
const char* password = "*************";

// Add your MQTT Broker IP address, example:
//const char* mqtt_server = "192.168.1.144";
const char* mqtt_server = "****";
const char* user = "******";
const char* user_pwd = "*****";

// Set your Static IP address & Gateway IP address -> Consomation réduite (/DHCP)
IPAddress local_IP(192, 168, 1, 10);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

WiFiClient espClient;
PubSubClient client(espClient);

#define WIFI_TIMEOUT 10000      /* 10 secondes in milliseconds */
#define GLOBAL_TIMEOUT 15000    /* 20 secondes in milliseconds */
#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */

unsigned long chronoGlobal = millis(); // Initialisation Chrono time_timeout

// Batterie
float bat = 0;
int bat_pourcentage = 0;
float bat_volt = 0;

RTC_DATA_ATTR int previous_day = 0;
RTC_DATA_ATTR bool autorisation_envoi_Nbat = true;

// Conversion EZTime to EPOCH
int Year_conv = 0;
int Mois_conv = 0;
int J_conv = 0;
int H_conv = 0;
int m_conv = 0;
int sec_conv = 0;

//Tempo Volet
const int Tempo = 1;             /* Tempo Volet ON actif (secondes) */
int TempoMS = Tempo * 1000;     /* Tempo Volet en ms) */

//Heures modulation temps DeepSleep
const int H1_Deepsleep = 5;
const int H2_Deepsleep = 11;
const int H3_Deepsleep = 16;
const int H4_Deepsleep = 23;

// Volet Pin
const int MB = 16;
const int DB = 17;
const int MH = 5;
const int DH = 21;

// Initialisation structure stockage temps
struct tm timeinfo;

unsigned int duree_sleep = 25; //4200 max

void get_time() {
  time_t now;
  time(&now);
  localtime_r(&now, &timeinfo);
}

void afficher_temps() {
  Serial.print("Année: ");
  Serial.println(timeinfo.tm_year+1900);
  Serial.print("Jour: ");
  Serial.println(timeinfo.tm_mday);
  Serial.print("Mois: ");
  Serial.println(timeinfo.tm_mon+1);
  Serial.print("Heure: ");
  Serial.print(timeinfo.tm_hour);
  Serial.print(":");
  Serial.print(timeinfo.tm_min);
  Serial.print(":");
  Serial.println(timeinfo.tm_sec);
}

int ConvEZTime() {
  time_t t_of_day; 
  struct tm t;   
  t.tm_year = Year_conv-1900;
  t.tm_mon = Mois_conv-1;           // Month, 0 - jan
  t.tm_mday = J_conv;          // Day of the month
  t.tm_hour = H_conv;
  t.tm_min =  m_conv;
  t.tm_sec = sec_conv+1;
  t_of_day = mktime(&t);
  
  return t_of_day;
}

void Set_time() {
  int epoch_time = ConvEZTime();
  timeval epoch = {epoch_time, 0};
  const timeval *tv = &epoch;
  timezone utc = {0,0};
  const timezone *tz = &utc;
  settimeofday(tv, tz);
}

void calculDSleep(){
 get_time();
 if (timeinfo.tm_year+1900 < 2019) {
    duree_sleep = 25; //Durée par défaut Sleep (secondes)
    Serial.println("Année inférieur a 2019 - Pas de synchro");
 }
 else
 { 
	if (timeinfo.tm_hour < H1_Deepsleep)
	{
	 duree_sleep = 3600; //Durée augmenté Sleep (secondes)
	}
	else if (timeinfo.tm_hour < H2_Deepsleep && timeinfo.tm_hour > H3_Deepsleep)
	{
	 duree_sleep = 3600; //Durée augmenté Sleep (secondes)
	}
    else if (timeinfo.tm_hour > H4_Deepsleep)
    {
     duree_sleep = 3600; //Durée augmenté Sleep (secondes)
    }
	else
	{
		duree_sleep = 25; //Durée par défaut Sleep (secondes)
	}
 } 
}

void goToDeepSleep()
{
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  esp_wifi_stop();
  Serial.println();
  calculDSleep();
  Serial.print("Temps de sommeil (en s): ");
  Serial.println(duree_sleep);
  afficher_temps();
  esp_sleep_enable_timer_wakeup(duree_sleep * uS_TO_S_FACTOR);
  esp_deep_sleep_start();
}

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

 /*if (!WiFi.config(local_IP, gateway, subnet)) {
   Serial.println("STATIC IP Failed to configure");
  } */
  WiFi.begin(ssid, password);
  unsigned long startAttemptTime = millis(); // Chrono 1er connection
  while (WiFi.status() != WL_CONNECTED && 
          millis() - startAttemptTime < WIFI_TIMEOUT) {
    delay(500);
  }

  if(WiFi.status() != WL_CONNECTED){
    Serial.println("WIFI CONNECTION FAILED");
    goToDeepSleep();
  }  
  //Serial.println("");
  //Serial.println("WiFi connected");
  //Serial.println("IP address: ");
  //Serial.println(WiFi.localIP());
}

// Mesure de la tension et estimation du niveau de batterie (%) pour envoi MQTT
void batterie()
{
  bat = analogRead(35);
  bat_volt = (bat * 7.65)/(4096); //7.445
  char batVString[8];
  dtostrf(bat_volt, 1, 2, batVString);
  //Serial.print("Voltage batterie ");
  //Serial.println(batVString);
  client.publish("esp32/V_battery", batVString);
  bat_pourcentage =((-0.9759)*pow(bat_volt,3)+11.58*pow(bat_volt,2)-(44.232*bat_volt)+54.861)*100;
    if (bat_pourcentage > 100){
     bat_pourcentage = 100;
    }
  char batPString[8];
  dtostrf(bat_pourcentage, 1, 2, batPString);
  //Serial.print("Poucentage batterie ");
  //Serial.println(batPString);
  delay(200);
  client.publish("esp32/p_battery", batPString);
}

// MQTT
void callback(char* topic, byte* message, unsigned int length) {
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  String messageTemp;
  
  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    messageTemp += (char)message[i];
  }
  Serial.println();

  // Feel free to add more if statements to control more GPIOs with MQTT

  // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". 
  // Changes the output state according to the message
  if (String(topic) == "esp32/output") {
    //Serial.print("Changing output to ");
   if (messageTemp == "Pause"){
    client.publish("esp32/Etatvolet", "Pause");
    Serial.println("Sleep - Pause");
    goToDeepSleep();
      }
   else {
      if(messageTemp == "MBon"){
        //Serial.println("MBas on");
        digitalWrite(MB, HIGH);
        delay(TempoMS);
        digitalWrite(MB, LOW);
        client.publish("esp32/Etatvolet", "1"); //Confirmation reception ordre
      }
      else if(messageTemp == "DBon"){
        //Serial.println("DBas on");
        digitalWrite(DB, HIGH);
        delay(TempoMS);
        digitalWrite(DB, LOW);
        client.publish("esp32/Etatvolet", "1");
      }
      else if(messageTemp == "MHon"){
        //Serial.println("MHaut on");
        digitalWrite(MH, HIGH);
        delay(TempoMS);
        digitalWrite(MH, LOW);
        client.publish("esp32/Etatvolet", "1");
      }
      else if(messageTemp == "DHon"){
        //Serial.println("DHaut on");
        digitalWrite(DH, HIGH);
        delay(TempoMS);
        digitalWrite(DH, LOW);
        client.publish("esp32/Etatvolet", "1");
      }
      else if(messageTemp == "BAT"){
        delay(500);
        batterie();
        client.publish("esp32/Etatvolet", "1");
      }
      else{
        Serial.print("Message different - Sleep");
        goToDeepSleep();
      }
    }
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP32Client", user, user_pwd)) {
      Serial.println("connected");
      // Subscribe
      if (!client.subscribe("esp32/output")) {
      Serial.println("Sleep Subscribe failed");
      goToDeepSleep();
      }
    } 
    else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.print("Go to sleep");
      goToDeepSleep();
    }
  }
}

void setup() {
  pinMode(MB, OUTPUT);
  pinMode(DB, OUTPUT);
  pinMode(MH, OUTPUT);
  pinMode(DH, OUTPUT);

  btStop();
  esp_bt_controller_disable();
  Serial.begin(115200);
  setup_wifi();
  get_time();
  afficher_temps();
  if(previous_day != timeinfo.tm_mday){ // Syncornisation 1 fois par jour - Si plus régulier utiliser "time_t lastNtpUpdateTime();"
	 if(waitForSync(5)) { //Attente syncro NTP Timeout => sec

	 Timezone France;
	 France.setLocation("Europe/Paris");
	 Serial.println("France: " + France.dateTime());

	 Year_conv = France.dateTime("Y").toInt();
	 Mois_conv = France.dateTime("n").toInt();
	 J_conv = France.dateTime("j").toInt();
	 H_conv = France.dateTime("H").toInt();
	 m_conv = France.dateTime("i").toInt();
	 sec_conv= France.dateTime("s").toInt();

	 Set_time();
   previous_day = J_conv;
    }
   else{
     Serial.println("Echec Synchronisation");
   }
  autorisation_envoi_Nbat = true; //Autorise l'envoi du niveau de batterie
  }
  client.setServer(mqtt_server, 1883); //MQTT
  client.setCallback(callback); //MQTT
}

void loop() {
  while (millis() - chronoGlobal <= GLOBAL_TIMEOUT) {
    if (!client.connected()) {
     reconnect();
    }
    get_time();   
    if (timeinfo.tm_hour > H2_Deepsleep && timeinfo.tm_hour < H3_Deepsleep && autorisation_envoi_Nbat == true) {    // envoi batterie
      delay(500);                        // Evite la mesure du pique de tension au démarrage ?
      batterie();
      autorisation_envoi_Nbat = false;
    }
    delay(10);
    client.loop(); //Necessaire pour maintenir la conection MQTT
  }
  Serial.print("Global Timeout"); 
  goToDeepSleep(); //En cas d'impasse dans le programme -> Sommeil profond pour ne pas vider la batterie
}

Nota : Je suis loin d’être un expert en programmation, si vous rencontrez des bugs ou si vous avez des suggestions d’améliorations je serais très content de les entendre.
Nota 2 : Il existe une dérive notable de la l’horloge interne en fonction des modèles la fréquence de synchronisation est donc à adapté avec son application (pour mon application 1 fois par jour me semble suffisant)
Nota 3 : La bibliothèque EZtime simplifie beaucoup la programmation de la synchronisation NTP, mais une conversion est nécessaire pour enregistrer le temps dans l’horloge interne de l’ESP32

Tu peux regarder du coté Mysensors, cela vaudrait la peine de tester en 3v si cela fonctionne ou mettre un petit convertisseur 3v vers 5v à quelques centimes sur Aliexpress

Merci pour ton retour SWR,
En effet ça sera très facile d’utiliser ça au niveau programmation mais ça me pose deux problèmes : le 1er c’est que je voudrais un minimum de sécurité vu que ça va être monté sur des volets de baies vitrées et le deuxième c’est que si on fait un rapide calcul de consomation de l’arduino et du relais je ne tiendrais jamais plus de quelques semaines avec ma pile 3V ? :confused:

Bonjour,

Et tu veux une alim sur pile pour qu’elle raison ? Parce que tu n’as pas de courant à proximité ?
Car Il existe des relais contact sec pouvant être alimenté avec une source de type différent que ce qu’il contrôle ; je veux dire que la tension peut être différente ainsi que courant alternatif / continu.

bonsoir,
Avec un esp32 et batterie imr18650 car ils savent descendre trés bas en conso. Vous les commandez en mqtt avec retour d’état.

Bonjour Mips,

Merci pour ton retour,
La raison principale de l’alimentation sur batterie est effectivement le fait que je n’ai pas de courant a proximité. Dans l’idéal je voudrais quelque choses d’autonome et compacte. De cette façon je pourrais l’intégrer proprement à l’intérieur de mes télécommandes murales.

Merci pour la piste PanoLyon !
Je vais regarder ça de plus près. Ça semble facile à intégrer, visiblement c’est utilisé le plus souvent avec du MQTT ? Est-ce que tu as des retours sur la sécurité ?

Bonsoir,
pour ce qui est de la sécurité je ne suis pas spécialiste mais tu peux demander un nom d’utilisateur et un mot de passe pour t’abonner au broker. Pour ce qui est de l’épreuve dans le temps : 0 plantage de mosquitto en 2 ans.
En plus c’est pas mal pour l’endormissement de l’esp car :
1-depuis jeedom tu allumes avec un topic tableau/cmd = 1.
2-ton esp se réveille
2-1 se connecte en wifi ou autre
2-2 s’abonne au broker récupère le topic tableau/cmd
si = 0 sommeil directe.
sinon il allume ton tableau et peut plublier à son tour tableau tableau/result =1 ce qui fait ton retour d’état pour jeedom
3-Sommeil
et on recommence.
avantage économie de batterie, inconvénient une certaine latence qui dépendra du temps de sommeil.

Un petit comparatif ?
https://projetsdiy.fr/quelle-carte-esp32-choisir-developper-projets-diy-objets-connectes/
ça peut aider :kissing_smiling_eyes:
hésite pas si besoin

Bonjour !

Bon j’ai traîné un peu… le temps d’avoir le matériel, et surtout que ça fonctionne :
Je me suis trouver un lolin D32, merci pour le comparatif : très appréciable!
J’ai tenter de coder quelque chose de fonctionnel en IDE (à défaut d’être beau pour le moment…) en reprenant tes explications, divers tutoriels et des brides programmes à droite à gauche. Grace à cela la ESP32 est sur batterie (mode Deepsleep) et interfacé avec Jeedom par du MQTT : tout pour être heureux.
Seulement il arrive que au bout de quelques centaines de reboot le ESP32 s’arrête au milieu de rien et me vide la batterie…
J’ai donc rajouter des boucles « timeout » partout qui scrute depuis combien de temps la carte tourne et relance le Deepsleep si rien ne s’est passé. Mais visiblement ça ne suffit pas, ce n’est pas « stable » pour autant et impossible pour moi de comprendre exactement pourquoi.
J’imagine que je n’ai pas la bonne structure mais je suis un peu dans l’impasse…
Malgré tout voici le code si quelqu’un est intéressé. Je suis preneur de toutes les idées d’améliorations, code, conseils etc. Même si je doit reprendre le programme a 0.

Merci d’avance !

Relay_Fonctionnel_Jeedom_V3.ino.txt (6,4 Ko)

Par rapport au programme :
J’utilise différents topics pour permettre de déclencher des boucles via Jeedom. A la fin de chaque boucle il y a un remonté d’info via un autre topic. Jeedom peut alors remettre le topic « Pause » actif et faire basculer le ESP32 dans la boucle Deepsleep.

Bonjour @Willoug
Je vais jeter un oeil à ton programme (je ne suis pas spécialiste mes connaissances viennent du même fournisseur que toi :innocent:) et en profiter pour voir le fonctionnement du deep sleep merci.

Juste à la lecture de ton message je ne vois pas pourquoi ça planterait mais as tu laissé tourner avec le moniteur série ?

Alimentes tu tes relais avec la même alimentation (ta batterie) ? ce plantage n’interviendrait il pas au collage ou décollage du relais ?

je m’oriente sur l’alimentation car l’esp32cam quand il bosse, il est sensible sur son alimentation …
j’ai eu le souci avec un regulateur sur breadboard qui chauffait … et hop reboot et message sur la raison du reboot au sujet d’un pb d’alimentation…

voici mes premières idées si ça peut t’aider

Ce sujet a été automatiquement fermé après 24 heures suivant le dernier commentaire. Aucune réponse n’est permise dorénavant.