Page 32 sur 50

Re: Régulation d'une chaudière Frisquet ECO radio System

Publié : 06 nov. 2020, 16:51
par Today2000
super travail les gars!

Je vais essayer de vous aider, toutefois j'ai encore quelques blocages sur ma solution par radio.

Je récupère bien les données en SDR et RFlink aucun problème.
Par contre au niveau émission je me suis rendu compte que la trame emise par Rflink est mal formaté.
J'arrive à allumer la chaudiere mais je ne peut jouer sur les parametres.

Est ce que quelqu’un y est arrivé en Rflink?
L'autre possibilité est d'emettre directement avec le raspberry avec Rpitx, mais je ne vois pas comment créer ma trame.

Sinon je me rabattrai avec plaisir sur la solution Frisquet-mqtt ;-)
D’ailleurs est-il possible de l'installer en parallèle du module radio, ainsi si ma solution bug, ma femme remet des piles dans la télécommande pour avoir le chauffage ;-)

Merci bien

Re: Régulation d'une chaudière Frisquet ECO radio System

Publié : 06 nov. 2020, 16:59
par christopheHD
@Today2000, j'ai tenté comme toi la solution RFlink mais je ne suis pas plus avancé que toi. J'ai simplement fait les mêmes constations concernant le décodage de RFlink.
Ce qui m'étonne, c'est que RFlink détecte du protocole X2D alors que la release note du firmware 48 indique clairement qu'il supporte le Vaillant VRT 340f qui utilise les mêmes trames que ERS.
J'ai désassemblé le firmware 48 pour tenter de trouver le label du protocole et pouvoir émettre une trame de type Vaillant VRT 340f, mais je n'ai rien trouvé.
J'ai voulu m'inscrire sur le forum officiel de RFLink (Lets control it) mais je n'ai jamais reçu le mail d'activation. J'hésite à envoyer un mail au responsable de RFlink pour lui demander de l'aide concernant le protocole Vaillant VRT 340f.

Re: Régulation d'une chaudière Frisquet ECO radio System

Publié : 06 nov. 2020, 17:34
par Today2000
@christopheHD, merci ca me rassure ;-)
Oui c'est une bonne idée d'essayer de prendre contact ca pourra surmement aider d'autre personne avec ce protocole.

As tu essayer avec Rpitx? (ou autre solution) ca fonctionne en replay de la trame, mais c'est un fichier son :? j'aimerai la formater correctement

Re: Régulation d'une chaudière Frisquet ECO radio System

Publié : 06 nov. 2020, 17:40
par Today2000
@tchuene, je pense que c'est bien de continuer la partie plus technique code sur GitHub et que tu inseres ton code Sketch Arduino décodage ERS au sein du projet afin de regrouper toutes les infos pour ceux qui souhaite le mettre en oeuvre.

Super ton article sur ton blog!

tchuene a écrit : 27 oct. 2020, 16:55 @Etimou: as-tu avancé sur tes relevés?

Pour ceux que ça intéresse j'ai fait un article pour décrire le décodage des trames et le montage Arduino associé:
https://antoinegrall.wordpress.com/deco ... squet-ers/

Re: Régulation d'une chaudière Frisquet ECO radio System

Publié : 07 nov. 2020, 22:51
par Buglover
Bonsoir

Voici le retour de mes expérimentations avec mon wemosD1.
J'ai fais bcp de captures pour essayer de bien comprendre le protocole, et surprise j'ai un zero de trop à la fin du premier octet (et donc un décalage de l'ensemble du message). Ainsi au lieu d'avoir un device ID qui commence par 7, le mien commence par 3,
Et lorsque je rejoue les commandes avec le zero supplémentaire, elle fonctionne.
Pour info, j'utilise les codes de @tchuene (en lecture & écriture) que j'ai modifié, j'ai rajouté la gestion du stuffing et bcp de log pour comprendre et le support de SysLog pour dumper les messages sur mon PI.

Voici la version pour lire les trames pour les courageux

Code : Tout sélectionner


// active/desactive les traces SYSLOG
//#define SYSLOG   

#ifdef SYSLOG
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Syslog.h>

// WIFI credentials
#define WIFI_SSID "********"
#define WIFI_PASS "********"

// Syslog server connection info
#define SYSLOG_SERVER "192.168.0.7"
#define SYSLOG_PORT 514

// This device info
#define DEVICE_HOSTNAME "wemosD1"
#define APP_NAME "my-app"

// A UDP instance to let us send and receive packets over UDP
WiFiUDP udpClient;

// Create a new syslog instance with LOG_KERN facility
Syslog syslog(udpClient, SYSLOG_SERVER, SYSLOG_PORT, DEVICE_HOSTNAME, APP_NAME, LOG_KERN);
#endif

volatile long duration = 0;
volatile long prev_time = 0;
volatile boolean data_dispo = false;
byte input = 4;
String trame[3];
byte  hex[20];
byte message = 0;
byte start = true;
byte intro = 0;
String prefixe = "1100";
int cpt = 1;

char text[50] ;


void setup() {
  Serial.begin(500000);
  Serial.println();
  Serial.println();

  #ifdef SYSLOG
  // We start by connecting to a WiFi network
  Serial.print("Connecting to ");
  Serial.println(WIFI_SSID);
  WiFi.begin(WIFI_SSID, WIFI_PASS);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  syslog.logf(LOG_ERR, "START");
  #endif



  attachInterrupt(digitalPinToInterrupt(input), declenche, CHANGE);
  memset(text, 0, 50);
  Serial.println("\nSTART\n");
  
 
}

void loop() {
  if (data_dispo == true) {    
    int bit_state = digitalRead(input);
    //if (bit_state == HIGH) Serial.printf("-");
    //else Serial.printf("_");
    
    if ((duration > 700) && (duration < 950)) { // pulse off court
      trame[message] = trame[message] + !bit_state;
    } else if ((duration > 1400) && (duration < 1950)) { // pulse off long
      // verifie qu'on commence avec un pulse long à 1
      if ((start == true) && (!bit_state == HIGH)) {
        trame[message] = trame[message] + !bit_state + !bit_state;
        start = false;
      } else if (start == false) {
        trame[message] = trame[message] + !bit_state + !bit_state;
      }
    } else {
      start = true; // debut d'une nouvelle trame
      if (trame[message].length() > 200) {
        message++;
        if (message > 2) {
          for (message = 0; message < 3; message++) {
                       
            for (int x = 0; x <= 50; x=x+4) {
              if (trame[message].substring(x,x+4).compareTo(prefixe) == 0) {
                intro++;
              } else {                
                break;
              }
            }
            String sortie = "";
            if (intro >= 6 ) {

              sortie = "";
              
              int nbBit = 0;
              int nbOne = 0;

              // décodage des bits de la trame: 00=0, 11=0, 10=1, 01=1
              for (int x = (intro*4); x <= trame[message].length(); x=x+2) {
                if ((trame[message].substring(x,x+2) == "00") or (trame[message].substring(x,x+2) == "11")) {
                  if (!((nbOne == 5) && (nbBit >= 8*7) && (nbBit <8*12)))     // gestion du Stuffing pour les octets entre 7 et 11 inclu
                    sortie = sortie + "0";                                                        
                  nbOne = 0;
                } else {
                  sortie = sortie + "1";
                  nbOne ++;
                }
                nbBit++;
              }

              Serial.printf("BIN = ");
              for (int cpt = 0; cpt<sortie.length() ;cpt++) {
                Serial.printf("%c",sortie.substring(cpt,cpt+1)[0]);
                if (cpt % 4 == 3) Serial.printf(" ");
                if (cpt % 8 == 7) Serial.printf(" ");
                
              }              
              Serial.printf("\n");


              // repartition en bytes    
              /*         
              Serial.printf("IN = ");
              for (int cpt = 0; cpt<trame[message].length() ;cpt++) {
                Serial.printf("%c",trame[message].substring(cpt,cpt+1)[0]);
                if (cpt % 8 == 7) Serial.printf(" ");
              }
              
              Serial.printf("\nOUT = ");
              for (int cpt = 0; cpt<sortie.length() ;cpt++) {
                Serial.printf("%c",sortie.substring(cpt,cpt+1)[0]);
                if (cpt % 8 == 7) Serial.printf(" ");
              }              
              Serial.printf("\n");
              */

              
              memset(hex,0,20);   

              strcpy(text,"");
              Serial.printf("\nHEX = ");
              for (int cpt=0; cpt<sortie.length(); cpt+=8) {
                hex[cpt / 8] = convert(sortie.substring(cpt,cpt+8));  
                sprintf(text,"%s%02X",text,hex[cpt / 8]);
                if ((cpt % 32) == 24) Serial.printf(" ");
                  
                if ((cpt % 32) == 24) sprintf(text,"%s ",text);             
                Serial.printf("%02X",hex[cpt / 8]);
                
              }
              Serial.printf("\n");
              

              /* RAPPEL (src https://antoinegrall.wordpress.com/decodage-frisquet-ers/)
                Octet 00 – 11111101 = 0xBF – Fixe, attitré à chaque chaudière
                Octet 01 – 01100111 = 0xE6 – Fixe, attitré à chaque chaudière
                Octet 02 – 11001111 = 0xF3 – Fixe, attitré à chaque chaudière
                Octet 03 – 00000000 = 0x00 – Fixe
                Octet 04 – 00000100 = 0x20 – Fixe
                Octet 05 – 00000000 = 0x00 – Fixe
                Octet 06 – 00000000 = 0x00 – Fixe
                Octet 07 – 11000001 = 0x83 – Variable, préchauffage eau
                Octet 08 – 10101010 = 0x55 – Variable, chauffage
                Octet 09 – 00000000 = 0x00 – Niveau pile ?
                Octet 10 – 10111111 = 0xFD – Fixe
                Octet 11 – 00100010 = 0x44 – Variable checksum
                Octet 12 – 11111111 = 0xFF – Fixe, fin du message
                Octet 13 – 00000000 = 0x00 – Fixe
               */

              
              bool err = 0;

              // ID de ma frisquet devrait etre fixe
              if (!((hex[0] == 0x3F) && (hex[1] == 0xE4) && (hex[2] == 0x0A))) {
                err += 1;
                Serial.printf("ID  error : %02X %02X %02X\n",hex[0],hex[1],hex[2]);
                
                #ifdef SYSLOG
                syslog.logf(LOG_INFO, "ID  error : %02X %02X %02X",hex[0],hex[1],hex[2]);
                #endif 
              }
              // Devrait etre fixe, mais bon ...
              if (!((hex[3] == 0x00) && (hex[4] == 0x10) && ((hex[5] == 0x00) || (hex[5] == 0x80)))) {
                err += 2;
                Serial.printf("FIX error : %02X %02X %02X\n",hex[3],hex[4],hex[5]);

                #ifdef SYSLOG
                syslog.logf(LOG_INFO, "FIX error : %02X %02X %02X",hex[3],hex[4],hex[5]);
                #endif 
              }

             // Trame corromptue ?
             if ((hex[8] == 0xFF) && (hex[9] == 0xFF)) {
                err += 4;
                Serial.printf("FF  error : %02X %02X %02X\n",hex[8],hex[9],hex[10]);

                #ifdef SYSLOG
                syslog.logf(LOG_INFO, "FIX error : %02X %02X %02X",hex[8],hex[9],hex[10]);
                #endif
              }
                          
              Serial.printf("VALUE %d   NUM %02X  COMMAND %02X   HEATING %3d  ERROR %d\n",message, hex[6],hex[7],hex[8],err);
              
              #ifdef SYSLOG
              syslog.logf(LOG_INFO, "VALUE=%d; NUM=%02X; COMMAND=%02X; HEATING=%03d ;ERROR=%d; HEX=%s",message, hex[6],hex[7],hex[8],err,text);              
              #endif
              
              intro = 0;
              
            } 
            else {    // pas de synchro 
              Serial.printf("SKIP [%d] = ", intro);
              
              for (int cpt = 0; cpt<8*8;cpt++) {
                Serial.printf("%c",trame[message].substring(cpt,cpt+1)[0]);
                if ((cpt % 4) == 3) Serial.printf(" ");
              }

              #ifdef SYSLOG
              syslog.logf(LOG_INFO, "SKIP [%d]", intro);
              #endif
              
              Serial.printf("\n");
            }
            
            Serial.println("----");
          }
           
          trame[0] = "";
          trame[1] = "";
          trame[2] = "";
          Serial.println();
          message = 0;
        }
      } else {
        trame[0] = "";
        trame[1] = "";
        trame[2] = "";
        message = 0;
      }
    }
    data_dispo = false;
  }
}

void declenche() {
  duration = micros()-prev_time;
  prev_time = micros();
  data_dispo = true;
}

byte convert(String entree) {
  byte result = 0;
  for (int f = 0; f <= 7 ; f++) {
    if (entree.substring(f,f+1) == "1") bitSet(result, f);
  }
  return result;
}

Re: Régulation d'une chaudière Frisquet ECO radio System

Publié : 08 nov. 2020, 21:40
par Buglover
Hello

Je continue mon message posté hier soir qui était un peu court.
Voici deux messages (avec les trames de synchro) capturés avec sur mon wemosD1 avec le programme plus haut en mode Hors Gel (soit relativement fix), c'est le meme motif pour les autres modes
-> 0000 3FE4 0A00 1000 0042 0000 FFBF 7F40 (trame brute - 135 bits = 16bytes et 7 bits)
-> 0000 7FC8 1500 2000 0084 0000 FE7F FF80 (trame avec un bit '1' rajouté au début, 136 bits = 17 bytes)

Et la bonne nouvelle, cette 2eme trame est presque parfaitement bien formée d'après la description de Kainhofer - en commençant par un 0x7F, avec 2 différences
  • le premier octet significatif 7F vs 7E, mais il est possible que l'ID soit stocké sur plus de bits que ce que Kainhofer l'imaginait)
  • Le dernier octet a le bit de poids fort à 1, alors qu'il devrait être à 0
Rappel de sa description
Image

J'ai fais au moins une cinquantaine de captures et ce schéma est relativement immuable. De plus, pour l'instant ma frisquet semble sourde aux trames officielles (136bits), et semble appréciée celle buggée (135 bits)

@tchuene et @etimou, en relisant vos posts vous ne semblez pas avoir ce problème donc il semble avoir des capteurs & Frisquet plus ou moins buggés vis à vis du protocol décrit.

Re: Régulation d'une chaudière Frisquet ECO radio System

Publié : 09 nov. 2020, 09:37
par etimou
Sauf erreur de ma part, le bit stuffing peut faire changer la longueur de trame en fonction du contenu. Il faut peut-être chercher de ce côté là. C'est peut-être un peu plus complexe que prévu.
Aussi tu as raison, rien n'indique que le 7E du début ne fasse pas partie (tout ou partiellement) de l'ID…

EDIT: ça peut aussi donner l'impression que tu as retiré un bit de bitstuffing là où il ne faudrait pas

Re: Régulation d'une chaudière Frisquet ECO radio System

Publié : 09 nov. 2020, 15:42
par tchuene
Si tu peux il faudrait que tu postes les 3 trames brutes non décodées (variables trame[1], trame[2], trame[3] dans le code) comme Etimou l'avait fait, pour en vérifier le format.

Re: Régulation d'une chaudière Frisquet ECO radio System

Publié : 09 nov. 2020, 18:24
par etimou
@tchuene, tu as pu avancer sur la commande 15 qui ne fonctionne pas?

Concernant la règle qui lie la température à la commande, j'ai l'impression qu'on est proche d'une simple règle linéaire:

Code : Tout sélectionner

temp = 0.5 * cmd + 20
Soit pour déterminer la commande à envoyer pour obtenir une température donnée:

Code : Tout sélectionner

cmd = 2 * (temp -20)
J'ai l'intention d'appliquer une loi d'eau https://fr.wikipedia.org/wiki/Loi_d%27eau pour calculer la température de l'eau du chauffage en fonction de la température extérieure. Je le fais aujourd'hui en manuel et ça me parait plutôt bien. J'ai une maison ancienne avec des gros radiateurs en fonte, et la régulation de l'air ambiant avec le satellite ERS était catastrophique. Ouvrir la porte 5 min revenait à mettre le chauffage à fond le temps de faire remonter la température, qui devenait ensuite trop élevée pendant un bon moment.

Puisque ma chaudière est désormais connectée à internet, j'envisage de récupérer la température extérieure sur un site du genre openweathermap.org (précision restant à vérifier) et même anticiper avec la température prévisionnelle qu'il fera dans une ou deux heure.

Re: Régulation d'une chaudière Frisquet ECO radio System

Publié : 09 nov. 2020, 19:50
par polo9222
@etimou : je pratique la loi d'eau depuis plus de deux ans maintenant avec d'excellents résultats.
Par rapport à la mise en œuvre expliquée dans Wikipedia, j'ai fait assez simple :
T° sortie = k + i* T°ext
En ayant déterminé k et i en statique hors régulation :
À 2 moments où la t° extérieure est très différente, je cherche (en manuel) quelle t° de sortie je dois mettre pour obtenir ma consigne stabilisée . Avec ces 2 points, je calculé k et i.
Ensuite en régulation, en fonction de l'écart entre consigne et t° ambiante, j'ajoute ou retranché 5°. (un cran).
Pas d intégrale, de dérivée ou autre.
Je régule ainsi une maison 3 niveau, 3 murs extérieurs à +/-0.2°. C'est très agréable.

Pour la sonde extérieure, j'ai une station netatmo et surtout une sonde 18sb20 sur un wemos d1.
Le plus difficile est de trouver un bon emplacement pour les sondes.....

J'ai hâte de recevoir mon matériel pour faire une régulation plus fine sur la base de vos travaux actuels.
L'avantage de la commande en // sur les boutons manuels comme qqun le disait précédemment, réside dans le fait que ma femme ou mes enfants peuvent rebasculer immédiatement en automatique Frisquet sans intervention mécanique/électrique sur la chaudière en cas de panne en mon absence (fréquente). Ce n'est pas encore arrivé 🤞😊.

Merci à tous pour vos essais et retours d'informations passionnants.

Portez-vous bien