Objet thermostat mysensors

Bonjour à tous

Je vous propose le partage d’une de mes réalisation (objet thermostat mysensors diy)

Au départ l’idée était de gérer le chauffage pièce par pièce

La domotique le fait aisément mais la modification d’une consigne température d’une pièce impose de sortir le téléphone portable ou d’aller pianoter sur une la tablette lorsque le système en est pourvu.

J’ai donc réalisé des thermostats autonomes à disposer dans chacune des pièces à gérer.

Ils permettent la modification de la consigne en local (madame est contente) tout en remontant l’information à jeedom qui a toujours la charge de gérer le chauffage de la pièce concernée.

On a donc 2 sources de modifications de consigne : en local et par jeedom

Bien entendu lorsque jeedom modifie une consigne, (passage en mode éco, mode nuit ect …) elle est transmise à l’objet thermostat lors de la prochaine communication.

Pour ceux qui sont intéressé par la réalisation je partage :

-le pcb (easyeda.com faire recherche thermostat mysensors jlb)

-le boitier imprimé en 3d (tinkercad.com faire recherche thermostat mysensors jlb)

-le scketch arduino ci-joint

pour ceux qui veulent réaliser, n’hésitez pas à me demander si besoin

Jean-luc

Manuel carte thermostat V16.pdf (255,7 Ko)

/**
 * The MySensors Arduino library handles the wireless radio link and protocol
 * between your home built sensors/actuators and HA controller of choice.
 * The sensors forms a self healing radio network with optional repeaters. Each
 * repeater and gateway builds a routing tables in EEPROM which keeps track of the
 * network topology allowing messages to be routed to nodes.
 *
 * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
 * Copyright (C) 2013-2015 Sensnology AB
 * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
 *
 * Documentation: http://www.mysensors.org
 * Support Forum: http://forum.mysensors.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 *********************************************************************
 *
  */
/*********************************************************************
Thermostat JLB le 15/02/2019
Afficheur lcd nokia 5110
Arduino Pro Mini ATmega328 3.3V 8MHz sur piles
 * envoi la température touts les x mn (modifiable)
 * envoi température si non envoyée depuis 60mn
 * envoi la tension de batterie toute les 12 heures
 * comms avec ack 
 * affichage du score sur 10 des dernières comms réussits
 * possibilité de changer la frequence de réveil au démarrage du programme (entre 1 et 15 minutes)
*********************************************************************/

// Enable debug prints to serial monitor
//#define MY_DEBUG 

// Enable and select radio type attached
#define MY_RADIO_RF24

#define MY_TRANSPORT_WAIT_READY_MS 1  // important pour fontionnement en local en cas de gateway hs
uint8_t parent_id = 0;
#define MY_PARENT_NODE_ID parent_id
#define MY_PARENT_NODE_IS_STATIC

#include <SPI.h>
#include <MySensors.h>  
#include <DallasTemperature.h>
#include <OneWire.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

#define bt_up           3   // Arduino Digital I/O pin number for button 
#define bt_down         2   // Arduino Digital I/O pin number for button 
#define retroeclairage  A2  // Arduino Digital I/O pin number for retroeclairage
#define MARCHE  0 
#define ARRET   1 


byte total_score = 0 ;      // score sur 10 des coms réussis pour affichage en local
bool busy = false ;
bool comm = true ;
bool reception = false ;
bool ack = false ;
unsigned long compteur1 = 0;        // pour température
unsigned long compteur2 = 0;        // pour batterie
int debug = 0;                      // mettre à 1 pour affichage sur moniteur ******************************************************************************************************
int frequence = 5;                  // frequence des réveils en minutes (ajustable entre 1 et 15 minutes en local)
unsigned long SLEEP_TIME = 300000 ; // Sleep time between reads (in milliseconds) toutes les 5 minutes (5*60*1000)
float temperature = 0;
float lastTemperature = 0;
float consigne_jeedom = 0;          // consigne thermostat venant de jeedom
float consigne_manu = 0;            // consigne donnée en local
float batt ;
int my_id ;
float offset_temperature = 0;         // décalage capteur de température
int signe_offset = 0;                 // 0 pour positif et 1 pour négatif

OneWire oneWire(A1);                  // Bus One Wire sur la pin A1 de l'arduino
DallasTemperature sensors(&oneWire);  // Utilisation du bus Onewire pour les capteurs
DeviceAddress sensorDeviceAddress;    // Vérifie la compatibilité des capteurs avec la librairie

int BATTERY_SENSE_PIN = A0;           // select the input pin for the battery sense point

// Initialize temperature message
MyMessage msgTemperature(0,V_TEMP);     // température
MyMessage msgConsigne(1,V_TEMP);        // consigne manu
MyMessage msgBattery(3,V_VOLTAGE);      // tension de battery
MyMessage msgEssai(4,V_TEMP);           // pour consigne jeedom

void before()
{
  parent_id = loadState(2);         // lecture en eeprom
  
  // Startup up the OneWire library
  sensors.begin();                                // Activation des capteurs
  sensors.getAddress(sensorDeviceAddress, 0);     // Demande l'adresse du capteur à l'index 0 du bus
  sensors.setResolution(sensorDeviceAddress, 12); // Résolutions possibles: 9,10,11,12
}

Adafruit_PCD8544 display = Adafruit_PCD8544(8,7,6,5,4); //(SCLK,DIN,D/C,CS,RST) pins (clk,din,dc,ce,rst)

void setup()   {  
  pinMode(bt_up, INPUT_PULLUP);     // set digital pin as input 
  pinMode(bt_down, INPUT_PULLUP);   // set digital pin as input             
  pinMode(retroeclairage, OUTPUT);
  digitalWrite(retroeclairage,ARRET);

  my_id = getNodeId() ;             // mon node id
  
  if (debug == 1) {
    Serial.print("Node_ID :"); Serial.println(my_id);
    Serial.println();
  }
  
  frequence = loadState(1);           // lecture en eeprom
  if (frequence<1 || frequence>15) { frequence = 1; }
  SLEEP_TIME = frequence * 60000 ;

  offset_temperature = loadState(3);  // lecture en eeprom
  offset_temperature = offset_temperature / 10;
  signe_offset = loadState(4);
  if (offset_temperature < 0 || offset_temperature > 1)  { offset_temperature = 0; }
  if (signe_offset) { offset_temperature = offset_temperature * -1; }
  
// Nokia 5110
  digitalWrite(retroeclairage,MARCHE);
  display.begin();                    // initialize the display
 
  display.setContrast(60);            // set the screen contrast to your liking
  display.clearDisplay();             // remove splash screen
       
  display.setTextSize(1);             // font size integer (2 is too large here)
  //display.setTextColor(BLACK);        // font "color"
  display.setCursor(0,0);            // cursor position (X,Y)
  display.setTextColor(WHITE, BLACK); // white text on black background
  display.println("Thermostat V16");
  //display.setCursor(8,10);
  //display.setTextColor(WHITE, BLACK); // white text on black background
  //display.println(" Ver: 14.0 ");
  display.setTextColor(BLACK);        // font "color"
  display.setCursor(0,10);           // cursor position (X,Y)
  display.println("Node id  : ");
  display.setCursor(60,10);
  display.println(my_id,1);
  display.setCursor(0,20);           //cursor position (X,Y)
  display.println("Freq(mn) : ");
  display.setCursor(60,20);
  display.println(SLEEP_TIME/60000,1);
  display.setCursor(0,30);           //cursor position (X,Y)
  display.println("Parent id:");
  display.setCursor(60,30);
  display.println(parent_id,1);
  display.setCursor(0,40);           //cursor position (X,Y)
  display.println("Offset   :");
  display.setCursor(60,40);
  display.println(offset_temperature,1);
  
  display.display();                  //display text
  //wait(5000);

  for ( int i = 0 ; i < 5000 ; i++ ) {    // attente au demarrage pour changement frequence
    wait(1);
    if (!digitalRead(bt_up) || !digitalRead(bt_down)) {   // changement demandé
      display.clearDisplay();             // remove splash screen
      display.setTextColor(WHITE, BLACK); // white text on black background
      display.println(" Parametrage  ");
      display.setTextColor(BLACK); // white text on black background
      display.setCursor(0,20);            // cursor position (X,Y)
      display.println("Freq(mn) : ");
      display.setCursor(60,20);
      display.println(SLEEP_TIME/60000,1);
      display.display();                  //display text
      change_frequence ();
      
      if (SLEEP_TIME == 0) {   // reset node id
        for (uint16_t i=0; i<EEPROM_LOCAL_CONFIG_ADDRESS; i++) {
          hwWriteConfig(i,0xFF);
        }
        display.clearDisplay();             // remove splash screen
        display.setTextColor(BLACK);        // font "color"
        display.setCursor(0,10);            // cursor position (X,Y)
        display.println("Raz nodeID ok");
        display.setCursor(0,20);            // cursor position (X,Y)
        display.println("FAIRE RESET...");
        display.display();                  //display text
        sleep(3600000);       // il faut redémarrer la carte après la config
      }
      
      display.clearDisplay();             // remove splash screen
      display.setTextColor(WHITE, BLACK); // white text on black background
      display.println(" Parametrage  ");
      display.setTextColor(BLACK); // white text on black background
      display.setCursor(0,20);            // cursor position (X,Y)
      display.println("Parent id:");
      display.setCursor(60,20);
      display.println(parent_id,1);
      display.display();                  //display text
      change_parent ();

      // offset température
      display.clearDisplay();             // remove splash screen
      display.setTextColor(WHITE, BLACK); // white text on black background
      display.println(" Parametrage  ");
      display.setTextColor(BLACK); // white text on black background
      display.setCursor(0,20);            // cursor position (X,Y)
      display.println("Offset :");
      display.setCursor(50,20);
      display.println(offset_temperature,1);
      display.display();                  //display text
      change_offset_temperature ();
      
      saveState(2,parent_id);             // sauvegarde en eeprom
      frequence = SLEEP_TIME / 60000 ;
      saveState(1,frequence);             // sauvegarde en eeprom
      
      if (offset_temperature > 0) {       // positif
        saveState(4,0);
      }
      else  {                             // négatif
        saveState(4,1);
      }
      offset_temperature = offset_temperature *10;
      if (offset_temperature<0) { offset_temperature=offset_temperature *-1;  }
      saveState(3,offset_temperature);
      digitalWrite(retroeclairage,ARRET);    
      
      display.clearDisplay();             // remove splash screen
      display.setTextColor(BLACK);        // font "color"
      display.setCursor(0,20);            // cursor position (X,Y)
      display.println("FAIRE RESET...");
      display.display();                  //display text
      sleep(3600000);       // il faut redémarrer la carte après la config
      break ;
    }
  }
  digitalWrite(retroeclairage,ARRET);
  if (debug == 1) {
        Serial.print("Frequence (ms):"); Serial.println(SLEEP_TIME);
        Serial.println();
  }
  // requestTemperatures() will not block current thread
  sensors.setWaitForConversion(false);

  // use the 1.1 V internal reference
  #if defined(__AVR_ATmega2560__)
    analogReference(INTERNAL1V1);
  #else
    analogReference(INTERNAL);
  #endif
  compteur2 = 43200000/SLEEP_TIME ;   // pour envoyer la batterie au demarrage du prg
}

void presentation() {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo("Termostat", "15.0");
  present(0, S_TEMP);         // temperature
  present(1, S_TEMP);         // consigne manu
  present(3, S_MULTIMETER);   // batterie
  present(4, S_CUSTOM);       // consigne jeedom
}

// *****************************************************************************************************************
void loop()     
{
  static bool onetime = false ;
  // demande la consigne jeedom une seule fois au demarrage
  if (!onetime) { 
    demande_consigne ();
    batterie ();
    send(msgBattery.set(batt,2)); 
    onetime = true ; 
  }      
  
  if (!digitalRead(bt_up) || !digitalRead(bt_down)) {           // modif consigne en manuel
    // pour rapatriment consigne jeedom avant de la changer en manuel
    digitalWrite(retroeclairage,MARCHE); 
    demande_consigne () ;
    affichage();              // affichage en local
    change_consigne();        // modifie la consigne en manuel
    send_consigne () ;      // envoi la consigne modifiée en local
    affichage();            // affichage en local
  }

  else {                      // réveil sleeptime
    compteur1 ++;   // pour comptage des sleeptime
    compteur2 ++;   // pour compage 12 heures
    batterie () ;   // mesure la tension de batterie
    
    // Fetch temperatures from Dallas sensors
    sensors.requestTemperatures(); //Demande la température aux capteurs
    // query conversion time and sleep until conversion completed
    int16_t conversionTime = sensors.millisToWaitForConversion(sensors.getResolution());
    // sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater)
    wait(conversionTime);
    // Read temperatures and send them to controller 
    // Fetch and round temperature to one decimal
    temperature = static_cast<float>(static_cast<int>(sensors.getTempCByIndex(0) * 10.)) / 10.;
    temperature=temperature+offset_temperature;
    // envoi la température si changement de température ou si pas d'envoi depuis 1 heure et pas d'erreur 
    if ((lastTemperature != temperature || compteur1 >= (3600000/SLEEP_TIME)) && temperature != -127.00 && temperature != 85.00) {
      compteur1 = 0;                                     // raz compteur
      lastTemperature = temperature;                    // sauve la nouvelle température pour prochaine comparaison
      send_temperature() ;    // envoie le nouvelle température à jeedom
      demande_consigne ();    // demande la consigne à jeedom
    }
    
    // envoi la batterie 1 fois par 12 heure
    if (compteur2 >= 43200000/SLEEP_TIME) {   // 12*60*60*1000
      compteur2 = 0;
      send(msgBattery.set(batt,2));           // sans demande ack
    }    // fin if
    
    affichage();                              // affichage en local
  }   // fin else
  wait(200);
  // Sleep for a while to save energy réveil sur sleep time ou sur interrupt
  sleep(digitalPinToInterrupt(bt_up), CHANGE, digitalPinToInterrupt(bt_down), CHANGE, SLEEP_TIME);
}     // fin loop
// *****************************************************************************************************************

/* ======================================================================
Function: batterie
// mesure la tension de batterie
====================================================================== */
void batterie ()  {

  int sensorValue = analogRead(BATTERY_SENSE_PIN);    // get the battery Voltage
      // 1M, 300K divider across battery and using internal ADC ref of 1.1V
      // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
      // ((1e6+300e3)/300e3)*1.1 = Vmax = 4.76666 Volts
      // 4.76666/1023 = Volts per bit = 0.004659498
      int batteryPcnt = sensorValue / 10;
      batt = sensorValue * 0.004659498 ;
      //int batt = sensorValue * 0.004664342 * 100;  
      if (debug == 1) {
        Serial.print("battery :"); Serial.println(batt);
      }
}

/* ======================================================================
Function: affichage
// affichage sur lcd nokia
====================================================================== */
void affichage () {
  //display.drawRect(25,18,10,10,BLACK);
  //display.drawRoundRect(47,18,10,10,2,BLACK);
  //display.display();
  display.clearDisplay();
  //display.drawRoundRect(0,0,84,48,2,BLACK);
  display.drawLine(0,24,84,24,BLACK);
  
  // battery icon
  int x = 71 ;
  int y = 29 ;
  display.drawLine(x-3,24,x-3,84,BLACK);
  
  display.drawRoundRect(x,y,10,15,2,BLACK);
  display.drawRect(x+2,y-1,6,1,BLACK);
  if (batt >= 3) { display.drawRect(x+2,y+11,6,2,BLACK); }    // 1 iere barre
  if (batt >= 3.33) { display.drawRect(x+2,y+8,6,2,BLACK); }  // 2 ieme barre
  if (batt >= 3.66) { display.drawRect(x+2,y+5,6,2,BLACK); }  // 3 ieme barre
  if (batt >= 4) { display.drawRect(x+2,y+2,6,2,BLACK); }     // 4 ieme barre
    
  display.setTextColor(BLACK);        //font "color"
  display.setTextSize(1);
  display.setCursor(9,0);
  display.print("temperature");
  display.setTextSize(2);
  display.setCursor(14,9);
  display.print(temperature,1);
  //display.drawRect(68,14,16,11,BLACK);
  display.setTextSize(1);
  display.setCursor(70,16);
  display.print(total_score);
  
  if (busy) {
    display.fillRect(15,32,50,15,WHITE);
    display.display();
    display.setTextColor(BLACK);        //font "color"
    display.setTextSize(2); display.setCursor(10,30); display.print("BUSY.."); display.display();
  }
  else if (comm) {
    display.setTextColor(BLACK);
    display.setTextSize(1);
    display.setCursor(12,24);
    display.print("consigne");
    display.setTextSize(2);
    display.setCursor(12,32);
    display.print(consigne_manu,1);
  }
  else {
    display.setTextColor(WHITE, BLACK); //white text on black background
    display.setTextSize(1);
    display.setCursor(1,31);
    display.print(" No comm...");
  }
  display.display();  
}

/* ======================================================================
Function:send_consigne
// envoi la nouvelle consigne à jeedom
// 3 tentatives si pas reception ack
====================================================================== */
void send_consigne () {
  affichage() ;
  comm = false ;        // com est utilisé dans affichage
  for ( int i = 0 ; i < 3 ; i++ ) {
    send(msgConsigne.set(consigne_manu, 2), true);  // envoie la nouvelle consigne à jeedom avec ack et 3 tentavives
    if (reception_ack()) {
      comm =true ;
      break ;
    }
  }
  busy = false ;
}

/* ======================================================================
Function:send_temperature 
// envoi la température à jeedom 
// 3 tentatives si pas reception ack
====================================================================== */
void send_temperature () {
  affichage() ;
  comm = false ;        // com est utilisé dans affichage
  for ( int i = 0 ; i < 3 ; i++ ) {
    send(msgTemperature.setSensor(0).set(temperature,1),true);   // envoie le nouvelle température à jeedom avec ack
    if (reception_ack()) {
      comm =true ;
      break ;
    }
  }
  busy = false ;
}

/* ======================================================================
Function:demande_consigne 
// demande la consigne jeedom à la gateway
// 3 tentatives si pas de reception
====================================================================== */
void demande_consigne () {
  busy = true ;
  affichage() ;
  comm = false ;        // com est utilisé dans affichage pour affichage consigne
  for ( int i = 0 ; i < 3 ; i++ ) {
    request(4,V_VAR5,0);
    if (reception_request()) {
      comm =true ;
      busy = false ;
      break ;
    }
  }
  busy = false ;
}

/* ======================================================================
Function: change_consigne
// incrémente / décrémente la consigne en manuel (entre 1 et 23 degrés)
// sortie au bout de 3 secondes si pas de bouton appuyé
====================================================================== */
void change_consigne () {
  unsigned long previousMillis = 0 ;
  unsigned long interval = 3000 ;  // 3 secondes
  bool timeout = false ;

  wait(200);
  previousMillis = millis() ;
  consigne_manu = consigne_jeedom ;  
  digitalWrite(retroeclairage,MARCHE);
  while (! timeout) {
    if (!digitalRead(bt_up)) {                          // bouton  up enfoncé
      consigne_manu = consigne_manu + 0.5 ;
      if (consigne_manu > 23) { consigne_manu = 23 ; }
      affichage();    // affichage en local
      wait(250) ;
      previousMillis = millis() ;
    }
    else if (!digitalRead(bt_down)) {                   // bouton down enfoncé
      consigne_manu = consigne_manu - 0.5 ;
      if (consigne_manu < 1) { consigne_manu = 1 ; }
      affichage();    // affichage en local
      wait(250) ;
      previousMillis = millis() ;
    }
    else {
      // aucun bouton enfoncé
    }
    if (millis() - previousMillis >= interval) {      // regarde si timeout
      timeout = true ;
    }
  }   // fin while
  digitalWrite(retroeclairage,ARRET);      
}   // fin void

/* ======================================================================
Function: change_frequence
// incrémente / décrémente la frequence de réveil
// sortie du void au bout de 5 secondes si pas de bouton appuyé
====================================================================== */
void change_frequence () {
  unsigned long previousMillis = 0 ;
  unsigned long interval = 5000 ;  // 5 secondes
  bool timeout = false ;

  wait(200);
  previousMillis = millis() ;
  digitalWrite(retroeclairage,MARCHE);
  while (! timeout) {
    if (!digitalRead(bt_up)) {                                // bouton  up enfoncé
      SLEEP_TIME = SLEEP_TIME + 60000 ;
      if (SLEEP_TIME > 900000) { SLEEP_TIME = 900000 ; }
      display.clearDisplay();
      display.setTextColor(BLACK);     // white text on black background
      display.setCursor(0,20);                // cursor position (X,Y)
      display.println("Freq(mn) : ");
      display.setCursor(60,20);
      display.println(SLEEP_TIME/60000,1);
      display.display();                      // display text
      wait(250) ;
      previousMillis = millis() ;
    }
    else if (!digitalRead(bt_down)) {                         // bouton down enfoncé
      SLEEP_TIME = SLEEP_TIME - 60000 ;
      if (SLEEP_TIME < 0) { SLEEP_TIME = 0 ; }
      display.clearDisplay();
      display.setTextColor(BLACK);     // white text on black background
      display.setCursor(0,20);                // cursor position (X,Y)
      display.println("Freq(mn) : ");
      display.setCursor(60,20);
      display.println(SLEEP_TIME/60000,1);
      display.display();                      // display text
      wait(250) ;
      previousMillis = millis() ;
    }
    else {
      // aucun bouton enfoncé
    }
    if (millis() - previousMillis >= interval) {              // regarde si timeout
      timeout = true ;
    }
  }   // fin while
  //digitalWrite(retroeclairage,ARRET);      
}   // fin void

/* ======================================================================
Function: change_frequence
// incrémente / décrémente la frequence de réveil
// sortie du void au bout de 5 secondes si pas de bouton appuyé
====================================================================== */
void change_parent () {
  unsigned long previousMillis = 0 ;
  unsigned long interval = 5000 ;  // 5 secondes
  bool timeout = false ;

  wait(200);
  previousMillis = millis() ;
  digitalWrite(retroeclairage,MARCHE);
  while (! timeout) {
    if (!digitalRead(bt_up)) {                                // bouton  up enfoncé
      parent_id = parent_id + 1 ;
      if (parent_id > 255) { parent_id = 255 ; }
      display.clearDisplay();
      display.setTextColor(BLACK);     // white text on black background
      display.setCursor(0,20);                // cursor position (X,Y)
      display.println("Parent id:");
      display.setCursor(60,20);
      display.println(parent_id,1);
      display.display();                      // display text
      wait(250) ;
      previousMillis = millis() ;
    }
    else if (!digitalRead(bt_down)) {                         // bouton down enfoncé
      parent_id = parent_id - 1 ;
      if (parent_id < 0) { parent_id = 0 ; }
      display.clearDisplay();
      display.setTextColor(BLACK);     // white text on black background
      display.setCursor(0,20);                // cursor position (X,Y)
      display.println("Parent id:");
      display.setCursor(60,20);
      display.println(parent_id,1);
      display.display();                      // display text
      wait(250) ;
      previousMillis = millis() ;
    }
    else {
      // aucun bouton enfoncé
    }
    if (millis() - previousMillis >= interval) {              // regarde si timeout
      timeout = true ;
    }
  }   // fin while
  //digitalWrite(retroeclairage,ARRET);      
}   // fin void

/* ======================================================================
Function: change_offset_temperature
// incrémente / décrémente l'offset de temperature
// sortie du void au bout de 5 secondes si pas de bouton appuyé
====================================================================== */
void change_offset_temperature () {
  unsigned long previousMillis = 0 ;
  unsigned long interval = 5000 ;  // 5 secondes
  bool timeout = false ;

  wait(200);
  previousMillis = millis() ;
  digitalWrite(retroeclairage,MARCHE);
  while (! timeout) {
    if (!digitalRead(bt_up)) {                                // bouton  up enfoncé
      offset_temperature = offset_temperature + 0.1 ;
      if (offset_temperature > 1) { offset_temperature = 1 ; }
      display.clearDisplay();
      display.setTextColor(BLACK);     // white text on black background
      display.setCursor(0,20);                // cursor position (X,Y)
      display.println("Offset :");
      display.setCursor(50,20);
      display.println(offset_temperature,1);
      display.display();                      // display text
      wait(250) ;
      previousMillis = millis() ;
    }
    else if (!digitalRead(bt_down)) {                         // bouton down enfoncé
      offset_temperature = offset_temperature - 0.1 ;
      if (offset_temperature < -1) { offset_temperature = -1 ; }
      display.clearDisplay();
      display.setTextColor(BLACK);     // white text on black background
      display.setCursor(0,20);                // cursor position (X,Y)
      display.println("Offset :");
      display.setCursor(50,20);
      display.println(offset_temperature,1);
      display.display();                      // display text
      wait(250) ;
      previousMillis = millis() ;
    }
    else {
      // aucun bouton enfoncé
    }
    if (millis() - previousMillis >= interval) {              // regarde si timeout
      timeout = true ;
    }
  }   // fin while
}   // fin void


/* ======================================================================
Function: reception_request
// attend la réception lors d'une demande de consigne à la gateway
// sortie au bout de 2 secondes si pas de reception
====================================================================== */
bool reception_request () {
  unsigned long previousMillis = 0 ;
  unsigned long interval = 2000 ;  // 2 secondes
  previousMillis = millis() ;
  reception = false ;
  while (! reception) {
    wait(1) ;
    if (millis() - previousMillis >= interval) {  // regarde si timeout
      score(0);
      return false ; // sortie sur timeout
    }
  }
  if (debug == 1) {
    Serial.print("Retournement request :"); Serial.println((millis() - previousMillis));
  }
  score(1);
  return true ;
}

/* ======================================================================
Function: reception_ack
// attend la réception
// sortie au bout de 2 secondes si pas de reception
====================================================================== */
bool reception_ack () {
  unsigned long previousMillis = 0 ;
  unsigned long interval = 2000 ;  // 2 secondes
  previousMillis = millis() ;
  ack = false ;
  while (! ack) {
    wait(1) ;
    if (millis() - previousMillis >= interval) {  // regarde si timeout
      score(0);
      return false ; // sortie sur timeout
    }
  }
  if (debug == 1) {
    Serial.print("Retournement ack :"); Serial.println((millis() - previousMillis));
  }
  score(1);
  return true ;
}

/* ======================================================================
Function: score
// score sur 10 des comms ok
====================================================================== */
void score (bool resultat) {
  static int pointeur ;
  static byte tableau [10];
  total_score = 0;
  pointeur ++ ;
  if (pointeur >9){ pointeur = 0;  }
  tableau [pointeur] = resultat ;
  for (int i = 0 ; i < 10 ; i++){
    total_score = total_score + tableau[i];
  }
  if (debug == 1) {
    Serial.print("Total :"); Serial.println(total_score);
    Serial.println();
  }
}

/* ======================================================================
Function: receive
Purpose : Mysensors incomming message  
Comments: reception de la consigne venant de la GateWay
====================================================================== */
void receive(const MyMessage &message) {
  if (message.isAck()) {
    ack = true ;
  }
  else {
    if (debug == 1) {
      Serial.print("sender : "); Serial.println(message.sender);
      Serial.print("type : "); Serial.println(message.type);
      Serial.print("sensor : "); Serial.println(message.sensor);
      Serial.print("destination : "); Serial.println(message.destination);
      Serial.print("valeur recu : "); Serial.println(message.getFloat());
    }
    
    if (message.type == V_VAR5 && message.sensor==4) {  // consigne recu de jeedom
      consigne_jeedom = message.getFloat() ;
      consigne_manu = consigne_jeedom ;
      reception = true ;
    }
  }
}
5 « J'aime »

Bonjour,

Impressionnant, beau boulot!
Je me le met sous le coude et merci pour le partage.

MmX

Oui, super réalisation, bravo.
Pour la batterie ?
Ça donne quoi comme autonomie ?

Bonjour Mmx, Bonjour rol-rider

Si vous voulez réaliser, n’hésitez pas à demander

Pour la batterie, charge complète du salon effectuée le 26/04/2019
Attention pas la batterie qui est sur mes photos (c’est de la m…)

il faut prendre : 5.79€ 55% de réduction|Liitokala – Pile Batterie Rechargeable Au Lithium, Parfait Pour Lampe De Poche Sans Carte Pcb, Originalité Ncr 18650b 3,7 V, 3400 Mah - Batteries Rechargeables - AliExpress

PNG

Courbe de décharge batterie (la fréquence de mesure est réglée à 5mn)

A+

Jean-luc

bonjour Jean-Luc,

Super intéressé par ce projet. Ma femme n’aime pas non plus sortir son tel.
J’aimerais deux thermostats comme ceux là : un pour la zone jour et un pour la zone nuit. J’ai déjà les deux thermostats virtuels Jeedom qui fonctionnent parfaitement. Je vais regarder cela avec attention.
Merci pour le boulot

Hello,

Jolie réalisation. Bravo.

Je vous évoque une autre solution pour tous ceux qui ne veulent pas bricoler. L’inconvénient est qu’il faut du 220v. Ça c’est facile à avoir. Il suffit de l’installer au mur au dessus d’une prise et passer les câbles dans le mur.
On peut acheter un thermostat WiFi BHT-6000 (environ 25€ Sur AliExpress) et l’inclure dans Jeedom avec le plugin WiFiLight2. Il y a un fil sur la communauté à ce sujet. Il sera possible d’utiliser ce thermostat pour télécommander le thermostat de Jeedom et utiliser sa sonde de température pour faire la régulation. Il est très réactif.

A+

1 « J'aime »

Merci @noBru77

Autre question, as tu optimisé le promini pour une basse consommation ? Ou tu n’as rien modifié sur le promini ?
En ce qui concerne la réalisation, j’en ai pas vraiment l’utilité, chauffage au fioul et présence quasi journalière, je change donc que deux fois la consigne par jour et jeedom le fait très bien tout seul.
Mais, j’avoue que ta réalisation et intéressante.

Bonjour rol-rider

oui promini 3.3V modifié :
-régulateur dessoudé
-led supprimée

j’ai également chauffage central radiateur eau chaude mais avec chaudière PAC
j’ai fait 7 circuits commandés par vannes motorisées et donc 7 thermostats

Bonjour axel

N’hésite pas à me demander si besoin

Bonjour jlb
Vraiment pas mal tes thermostats. J’ai pour le moment installé des sondes Mysensors dans chaque pièce. Peut être vois pour en remplacer quelques une par tes thermostats.

J’avais une autre question. Quelle vannes motorisée tu as mis et comment tu les pilotes ?
Je pense rajouter des vannes aussi pour un meilleur réglage du chauffage par pièce et plus d’économies.

Bonjour al85
j’ai 2 vannes motorisées boisseau sphérique Danfos HP A2 pour mes 2 gros secteurs (séjour + salle manger cuisine)
5 vannes motorisées à clapet TMOK TK360 pour les autres pièces (pas terrible ces vannes déja 2 pannes : roue dentée qui foire sur son axe cannelé)
Pour les piloter j’ai réalisé une carte 2 entrées 8 sorties (com mysensors)
elle gère :
les vannes, le circulateur avec les tempos pour éviter les coups de bélier
un watchdog de sécurité pour la com mysensors
timeout sur chaque vannes si la vanne reste ouverte trop longtemps
passage en manuel automatique en cas de défaut de com (dans ce cas le système fonctionne sur 2 secteurs piloté par mes anciens thermostats cablés sur les 2 entrée tor)
elle possède également une entrée température qui me sert à lire la temp. de mon ballon tampon

Je peux partager si tu veux

Capture1

Capture2

Bonjour jean-luc, je suis très interressé par ton projet, peux tu m’envoyer les éléments pour la réalisation .
Merci d’aance

Bonjour Lepecheur
Que te manque t’il pour réaliser ?

Bonjour Jean-Luc, peux tu me dire par qui tu es passé pour imprimer en 3D ton boitier?
Merci d’avance de ton retour

Bonjour Lepecheur
J’avais pas vu ton message

J’ai une Prusa I3 MK2 pour mes impressions 3D

OK, merci pour ton retour.
Pour ma part, je suis passé par une société française, 3DKfactory, très bien.
je suis en train d’en mettre un en oeuvre, mais je ne vois comment tu dechanche l’action sur le fil pilote dans tes scénarios

Bonjour Lepecheur
Tu fait un scénario ‹ gestion thermostat › comme expliqué dans manuel carte thermostat
puis 1 scénario pour chaque pièce pour déclencher le chauffage de la pièce

Désolé pour le délai.
OK, je vais essayer.
Je te tiens au courant

Bonjour,

N’ayant pas vos compétences techniques mais intéressé par votre réalisation, ne penseriez vous pas le vendre monté ?

Cordialement