Controle module DiO 433 MHz

Premier usage de mon montage RF 433 MHz : contrôler ds modules DIO (Chacon) pour prises encastrées.

En parcourant un peu de documentation, j’ai pu constater que grace au code RC-Switch, ça fonctionnait directement. J’ai donc tout mis en place, et j’ai enfoncé les boutons de la télécommande. Mais rien.

Naturellement, j’ai considéré que le problème venait de mes montages. J’ai donc tout repris, vérifié que le récepteur recevait bien des messages en provenance de l’émetteur. J’ai même flashé le récepteur avec un code plus rudimentaire, pour sniffer les ondes 443 MHz à plus bas niveau. Mais rien.

J’ai donc considéré qu’il ne me restait que deux possibilités :

  • soit mes modules et la télécommande ne fonctionnaient pas sur la même fréquence, contrairement à ce qui était annoncé,
  • soit la télécommande ne fonctionnait pas.

Pour confirmer la première hypothèse, il m’aurait fallut un SDR et sur l’instant, je n’en ai pas. J’ai donc entamée une procédure pour vérifier la seconde hypothèse. Et bingo, la télécommande ne contrôle même pas ses modules.

Grace à un article présentant une réparation, j’ai pu démonter cette télécommande et constater qu’en effet le résonateur est purement et simplement déssoudé. Après quelques manipulations au fer à souder, ça fonctionne de nouveau entre la télécommande et ses modules. Mais toujours sans grand succès avec RC-Switch.

Il est donc temps d’approfondir.

Collecte brute

Le protocole ne semblant pas reconnu par RC-Switch, il faut tenter de le découvrir. Et pour ça, première étape : on enregistre tout ce qui passe sur le 433.92 MHz, ne serait-ce que pour vérifier que la commande DiO fonctionne effectivement dans cette plage.

Pour ça, on utilise le programme SimpleRcScanner très légèrement adapté pour l’ESP8266.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#define SAMPLESIZE 500

static unsigned int timings[SAMPLESIZE];
static unsigned int pos = 0;
static unsigned long lastTime = 0;

static int receiverPin = 0;
static int interruptPin = 0;

void setup() {
  #ifdef ESP
  interruptPin = digitalPinToInterrupt(receiverPin);
  #else
  interruptPin = receiverPin;
  #endif
  Serial.begin(9600); 
  attachInterrupt(interruptPin, handleInterrupt, CHANGE);
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
}

void loop() {
    for (int i = 5; i>0; i--) {
      Serial.print(i);
      Serial.print("... ");
      delay(900);
      digitalWrite(13, HIGH);
      delay(100);
      digitalWrite(13, LOW);
    }
    Serial.println();
      
    detachInterrupt(interruptPin);
  
    int finalstate = digitalRead(receiverPin);
    
    char s = Serial.read();
    
    for (unsigned int i = pos + finalstate; i< SAMPLESIZE; i++) {
      Serial.print( timings[i] );
      Serial.print(",");
    }
 
    for (unsigned int i = 0; i < pos; i++) {
      Serial.print( timings[i] );
      Serial.print(",");
    }

    Serial.println("");
    Serial.println("Reset your Arduino to scan again...");

    while(true) {} 
  
}

void handleInterrupt() {
  const long time = micros();
  timings[pos] = time - lastTime;
  lastTime = time;
  if (++pos > SAMPLESIZE-1) {
    pos = 0;
  }
}

On obtient quelque chose comme :

120,116,192,740,352,1124,224,188,120,76,548,440,400,356,116,1148,260,408,568,752,464,1528,296,120,140,280,332,1080,92,612,392,92,600,452,1184,400,108,552,112,480,1200,468,128,532,1120,660,992,464,168,440,112,416,620,72,540,568,976,100,52,508,76,440,1228,472,116,432,1100,64,76,456,152,448,1192,388,200,476,104,384,1296,416,168,716,952,396,1264,428,192,392,1256,420,156,420,152,436,1256,412,1240,432,156,432,1252,440,156,388,1248,420,176,412,180,432,1228,384,200,416,1256,472,1180,412,212,428,1224,408,180,412,164,504,1160,388,208,468,1196,424,1244,400,200,368,216,340,1332,368,216,364,1308,344,236,352,1316,376,204,364,1308,368,10796,356,2772,368,216,364,1304,340,1320,356,236,368,1288,364,228,372,204,376,1304,372,1292,368,216,344,236,388,1276,388,200,376,1304,348,1308,364,244,352,236,344,1320,344,1316,364,228,348,1312,344,248,360,1304,348,236,356,1308,360,232,356,220,372,1300,372,208,372,1304,364,1300,356,244,356,1308,352,236,360,224,352,1328,352,1304,344,244,356,1304,364,228,348,1316,360,224,364,216,364,1316,364,212,360,1316,364,1292,368,232,364,1304,360,232,352,228,364,1316,344,232,348,1320,360,1304,356,232,364,220,360,1308,360,224,356,1316,356,220,360,1312,364,216,368,1300,360,10808,380,2744,392,188,392,1284,396,1260,400,192,392,1276,388,196,380,204,380,1292,380,1280,388,204,388,196,380,1292,380,200,384,1284,380,1284,384,216,388,200,384,1284,388,1272,388,204,384,1280,392,192,384,1284,384,208,380,1284,380,208,380,200,384,1288,384,204,376,1292,376,1284,388,216,380,1280,384,208,384,196,384,1288,388,1276,388,204,384,1276,392,200,388,1276,376,212,380,204,376,1296,384,200,376,1296,376,1284,384,220,380,1280,380,208,388,196,384,1288,380,204,384,1284,388,1276,384,208,384,196,380,1288,400,180,400,1272,400,180,404,1268,400,180,404,1264,396,10768,428,2704,432,148,432,1236,424,1240,428,164,428,1232,428,164,428,152,424,1252,424,1236,424,164,420,164,420,1252,424,156,424,1252,416,1244,420,184,416,164,416,1260,412,1248,424,168,420,1240,416,176,420,1244,412,176,420,1244,420,172,412,168,412,1260,416,164,412,1264,412,1248,416,188,416,1248,412,176,416,164,416,1260,416,1244,412,180,412,1252,412,180,

Après le bruit initial, on peut repérer des répétitions, ce qui rassure sur le fait que la commande fonctionne bien dans la plage de fréquence attendue. Il faut donc maintenant comprendre ce qui bloque RC-Switch.

Analyse du signal

En fouillant, on pourrait identifier des séquences et des valeurs canoniques. Mais le plus simple pour y voir plus clair consiste à passer par un outil dédié. Ce format est directement supporté par un outil proposé par sui. Il nous offre une visualisation graphique qui rend l’analyse bien plus simple.

On

Les protocoles RF 433 MHz semblent reprendre un principe universel : mettre un long signal bas, d’environ 10 ms. En se basant sur celui-ci, on comprend que le protocole ressemble à ce qui suit :

  • un séparateur de 380 µs environ,
  • un signal de 10 ms environ,
  • un signal de 2 ms environ,
  • un signal de 200 µs,
  • un signal de 160 µs.

Afin d’ajuster ces valeurs, après avoir supprimé la partie initiale de bruit, j’ai analysé les enregistrements avec triq.org après avoir converti le avec un commande du style tr ',' '\n' (remplacer les virgules par des sauts de ligne). On obtient alors des valeurs telles que :

Pulses	12× 161.7 ±10.0 µs	71× 210.3 ±38.0 µs	1× 412.0 ±0.0 µs	84× 1283.2 ±48.0 µs	3× 2740.0 ±34.0 µs	3× 10790.7 ±20.0 µs
Gaps	173× 383.8 ±46.0 µs
Periods	3× 11178.7 ±22.0 µs	3× 3137.3 ±2.0 µs	83× 586.7 ±32.0 µs	84× 1666.9 ±22.0 µs
Timings	3× 10790.7 ±20.0 µs	173× 383.8 ±46.0 µs	3× 2740.0 ±34.0 µs	72× 209.8 ±38.0 µs	84× 1283.2 ±48.0 µs	12× 161.7 ±10.0 µs

Et ne serait-ce que le double entête ne semble pas supporté par RC-Switch.

Gestion du protocole

En reprenant mes recherches sur Internet, je suis tombé sur les travaux de Charles GRASSIN. Mais les codes proposés ne fonctionnaient toujours pas avec mon équipement.

Sur la base de l’analyse précédente, j’ai ajusté les valeurs et… BINGO !

Pour décoder les messages, un petit soft DiOremoteRecordCode bien utile.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/*
  RecordCode.ino - Program to acquire the DiO modules On/Off codes
  Created by Charles GRASSIN, July 31, 2017.
  Under MIT License (free to use, modify, redistribute, etc.).
  www.charleslabs.fr

  This example captures codes sent by DiO 433MHz remotes. To read
  the frames, plug a RX 433MHz module to the Arduino, to pin 2.
  Open serial monitor at 9600 bauds. Aim the remote at the module,
  and the code will be display in the monitor. Capture "On" and "Off"
  codes.
*/

// --- HomeEasy protocol parameters ---
#define DiOremote_PULSEIN_TIMEOUT 1000000
#define DiOremote_FRAME_LENGTH 64
// Homeasy start lock : 2725 us (+/- 175 us)
#define DiOremote_START_TLOW 2550
#define DiOremote_START_THIGH 2900
// Homeeasy 0 : 210 us
#define DiOremote_0_TLOW 160
#define DiOremote_0_THIGH 260
//Homeeasy 1 : 1290 us
#define DiOremote_1_TLOW 1230
#define DiOremote_1_THIGH 1500

// --- Variables ---
const unsigned int RX_PIN = 2;  // 443 MHz rx module pin
unsigned long code = 0;         // Variable to store the code
int i    ;                      // Loop iteration variable
unsigned long t = 0;            // Time between two falling edges
byte currentBit,previousBit;

// --- Setup ---
void setup() {
  pinMode(RX_PIN, INPUT);
  Serial.begin(9600);
  Serial.println("Ready!");
}

// --- Loop ---
void loop() {
  // Wait for incoming bit
  t = pulseIn(RX_PIN, LOW, DiOremote_PULSEIN_TIMEOUT);

  // Only decypher from 2nd Homeeasy lock
  if (t > DiOremote_START_TLOW && t < DiOremote_START_THIGH) {
    code = 0;
    for (i = 0 ; i < DiOremote_FRAME_LENGTH ; i++) {
      // Read each bit (64 times)
      t = pulseIn(RX_PIN, LOW, DiOremote_PULSEIN_TIMEOUT);

      // Identify current bit based on the pulse length
      if (t > DiOremote_0_TLOW && t < DiOremote_0_THIGH)
        currentBit = 0;
      else if (t > DiOremote_1_TLOW && t < DiOremote_1_THIGH)
        currentBit = 1;
      else {
            Serial.print("Break at ");
            Serial.print(i);
            Serial.print(" with ");
            Serial.println(t);
        break;
      }
      
      // If bit count is even, check Manchester validity & store in code
      if (i % 2) {

        // Code validity verification (Manchester complience)
        if (!(previousBit ^ currentBit))
          break;
        
        // Store new bit
        code <<= 1;
        code |= previousBit;
      }
      previousBit = currentBit;
    }
  }

  // Send the code via serial
  if (i == DiOremote_FRAME_LENGTH) {
    Serial.println(code);
    Serial.println(code, HEX);
    Serial.println(code, BIN);
  }
}

Pour émettre des messages, un petit soft DiOremoteSendCode.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
  SendCode.h - Example of the library for controlling DiO devices.
  Created by Charles GRASSIN, July 31, 2017.
  Under MIT License (free to use, modify, redistribute, etc.).
  www.charleslabs.fr

  This exemple blinks the DiO device with a period of 4 second.
  Prior to using it, you *must* set the "on" and "off" values using
  the RecordCode example. These values are indeed unique to each 
  module.

  Pin 2 must be connected to a 433MHz Tx module.
*/

#include <DiOremote.h>

const int TX_PIN = 2; // Using Pin #D4

DiOremote myRemote = DiOremote(TX_PIN);

void setup()
{
  Serial.begin(9600);
  Serial.println("Ready to send!");
}

void loop() {
  if (Serial.available() > 0) {
    String code = Serial.readStringUntil('\n');
    Serial.print(" Sending ");
    Serial.println(code);

    myRemote.send(code.c_str());

    Serial.println("Ready to send!");
  }
}

Ce dernier s’appuie sur la librairie DiOremote écrite par Charles, dans laquelle j’ai ajusté mes valeurs. J’ai amorcé une copie de cette bibliothèque pour la gérer en configuration et recevoir des propositions d’évolution : https://github.com/guyou/DiOremote.

Références produit

Packaging :

  • Réf. 54797
  • DiO 1.0 433 MHz

Télécommande :

  • Ref 54760
  • Date code 1709

Références

Outils de visualisation :

Protocole DiO :