Protocole Somfy (Reverse engi RTS)

Hello tout le monde :wink:

Après avoir trouvé un peu de temps j'ai exporté plusieurs trames en csv dans le but d'essayer de les décoder et de trouver des points communs. J'ai essayé un codage en 8 bits.
Cependant ce n'est qu'après que je me suis rendu compte que les trames n'avaient pas toutes la même taille :stuck_out_tongue_closed_eyes:
Je vous lie donc le fichier que j'ai créer aujourd'hui avec plusieurs trames.

Thank for your precious help :~

bas.ods (20.5 KB)

Si je apporter ma pierre, EP1696402A1 - Système de communication avec compatibilité croisée et trame de communication associée - Google Patents donne quelques infos, comme la durée de la trame (140ms) et la taille des données (56bits)

thx je vais regarder ça :wink:

Hello,

j'avai déjà jeter un coup d'oeil sur ce protocol (plus bourrin je soude un fil entre la sortie du controlleur et l'emetteur RF sur une télécommande et j'analyse via la prise audio de mon pc, donc pas de parasite).
J'avais remarquer comme toi que le code ne change pas systématiquement mais plutot en fct du temps (je crois toutes les minute de mémoire).
Pour le reste, et meme si j'avai un signal propre, je n'ai pas su décoder la trame (ne sachant déjà pas si j'avai un 1 ou un 0 devant les yeux :smiley: )

Content de savoir que je ne suis pas le seul à galérer x)
J'essaye juste de me procurer une télécommande rts pas chère depuis un petit bout de temps pour pouvoir souder dessus sans prendre le risque de tuer ma seul télécomande (et donc mon volet par la même occas :grin: et puis comme ça, c'est moins bourrin) Puis j'essayerais de jeter un coup d'oeil du coté de la rom et de l'eeprom voir si il n'y a pas quelque chose d'intéressant ]:slight_smile:

Cependant comme je ne suis pas un pro dans ce domaine ^^ je risque de patauger un chouil au début :drooling_face:

Bonjour tout le monde, :wink:

Après avoir récupérer une ancienne télécommande RTS, j'ai essayé de lire le programme contenu dans le MCU, ce fut un echec cuisant, cependant je me suis penché sur la demande de brever que nous a donné mister mck21.
Il s'avère, que ce document est une véritable mine d'or, nous savons donc que :

  • La durée de transmission d’une trame complète selon le protocole RTS est de l’ordre de 140 ms, en incluant la synchronisation hardware, la synchronisation software
  • Que la trame est constitué au total de 56 bits
  • Qu'il utilise un code Manchester et contrôle systématiquement la fin de trame
  • un front montant représente un bit de logique 1 et un front descendant représente un bit de logique 0. :sweat_smile:
  • La trame contient un total de 56 bits
  • Le 1er octet (8 bits) ==> est une clé random pour le cryptage
  • Le 2nd octet (4 bits) ==> la commande (haut, stop, bas,...)
  • Le 3e octet (4 bits) ==> checksum
  • Le 4e et 5e octet (8 bits + 8 bits) ==> rolling code
  • 6e, 7e, 8e (8 bits + 8 bits + 8 bits) ==> adresse de l'émetteur

Voila qui va me faire avancer un peu plus. :stuck_out_tongue:

PS : ma télécommande de base semble utiliser la v1 du protocole RTS contrairement à la 2nd qui utiliserait la v2 (avec les 6 ou 12 bits de synchro obligatoires + infos entre les trames de bases).

Black_Ware:
Bonjour tout le monde, :wink:
...

Voila qui va me faire avancer un peu plus. :stuck_out_tongue:

PS : ma télécommande de base semble utiliser la v1 du protocole RTS contrairement à la 2nd qui utiliserait la v2 (avec les 6 ou 12 bits de synchro obligatoires + infos entre les trames de bases).

C'est bien de ne pas lacher "le morceau" :grin: mais il persiste là , un "bon paquet" d'inconnues à connaitre avant de resoudre simplement l'equation :smiley:

Salut à tous,

Ce sujet m'intéresse aussi. Je suis tombé sur le forum Arduino bien que ne faisant pas partie de la communauté (mais ca ne me fait pas peur de m'y mettre !)

En poussant mes recherches, je suis tombé sur ce lien (en anglais)

avec les détails techniques ici Somfy Smoove Origin RTS Protocol | PushStack
Et le résultat sur github radio_stuff/decode_somfy.c at master · dimhoff/radio_stuff · GitHub

C'est pour du Somfy US, mais on peut spéculé que le protocole est le même.

Voilà, j'espère que ca vous avancera, tenez le forum au courant des développement ! Je n'ai pas le matériel pour le moment pour me lancer dans les tests, mais je suis sûr que les plus avancés d'entre vous arriveront à quelque chose !

Salut Nikhosa,

Tout d’abord merci pour tes liens qui ont l'air à 1st vue, extrêmement prometteurs.
Je vais regarder tout ça à tête reposé dès demain si je trouve le temps. :grin:

Content de savoir que la communauté arduino à un nouveau membre ^^

Hi,

ok, I'm just try to log the signal with the arduino, but right now i'm hard working
about, because I'm just a beginner in programming, many years ago I program with Basic
on a Comodore C64/C128.
But in C I have to learn alot.

So I connect a Somfy remote with my Arduino Uno.
Ardunio should send the signal, maybe every 5 Sec, than after a little time should log
the signal on an SD card.
So the plan.

But I have a little Problem about sending, if i programm it, its send the whole time, even I stopp
it but arduino is log the signal.
But its really important to adjust the time when send, when log and in witch width it has to log every bit
In the analysis I found, the the minimum clock is 650 micro seconds, but if it is an Manchester, we have to look if it is 0 or 1 because I think the manchester is ls just looking is it going up to 1 oder down to 0

I'm also a very beginer in all of that.....

So hoping we can manage it together.

The background is, that I like to control my Somfy Motors in the house.
I know I can by an Ta Homa Box, but I don't like the system, that I have to bye an
expensiv Box and the rent an Server. I like that all in my network not in the internet....
If I like to controll, I will use an VPN direktly not over an external Server I cant control, but
the server owner can control.....

thanks
Jens

Bonjour,

Je confirme qu'en appliquant les indications données sur le site Somfy Smoove Origin RTS Protocol | PushStack (URL donnée dans un précédent post par nikhosa) j'arrive à lire les trames transmises par une télécommande TELIS ainsi qu'à piloter mes volets.

Matériel: ARDUINO UNO + module RR3-433 pour la réception + module RT4-433 pour l'émission (433.92 MHz).

A noter: un écart parfois jusqu'à 30% sur la durée des trames (entre les valeurs théoriques et les valeurs mesurées).

Je possède par ailleurs des volets d'une autre marque (télécommande M-SOFT, 868.3 MHz, qui semble émettre en FSK) et je suis preneur d'infos à ce sujet.

Lionel.

Bonjour yoyolb :wink:

Après de multiples essais, je n'arrive toujours pas à comprendre comment fonctionne le code decode_somfy.c
Pourrais-tu nous expliquer ta démarche ?

Merci

Black

Bonjour,

Je ne suis pas reparti du code "decode_somfy.c", ce n'est en effet pas du code arduino.
J'ai écrit un mini algo en me basant sur les infos du site "pushstack" (bravo à l'auteur au passage).

Testé en réception et en émission.

Je n'ai pas le code sous la main, j'essaye de vous le mettre à disposition ce soir.

NB: ce n'est qu'un prototype fonctionnel, loin d'être aussi élaboré que "decode_somfy.c".

Lionel.

Bonjour et merci de ta réponse :3

Oui en effet somfy_decoder.c est un programme que j'ai réussi à compiler sous linux mais après impossible d'en tirer quoi que ce soit, il me semble qu'il faut indiquer la trame en bit stream quelque part mais je ne sais pas si c'est dans le fichier remotes.txt ou en argument.

J'ai repris du coup la page du site à zéro mais cela reste encore un peu brouillon dans ma tête par exemple pour le rolling-code.
Et oui l'auteur de ce site a fait un boulot propre et complet. Chapeau à lui !

Et merci Lionel de nous aider :smiley:

Jo 8)

Bonsoir,

Comme promis ci-dessous mon code.
Quelques commentaires, à moitié en français... et à moitié en anglais...
La classe CCodecSomfyRTS se charge du décodage et de l'encodage.

Décodage:
=> appeler la méthode "pulse()" à chaque changement d'état (front montant / descendant) avec durée du pulse. La méthode se charge du décodage Manchester et stocke les données au fil de l'eau. Quand toute la trame a été reçue, appel à la méthode interne "decode()". Cette méthode décode la trame reçue, la vérifie (checksum) et affiche sur la console le message décodé (adresse, rolling code, touche pressée).

Emission:
=> appeler la méthode "transmit()" avec en paramètre le code de la touche à simuler ainsi que le rolling code courant.
NB 1: adresse actuellement en dur dans le code, à positionner manuellement (data[4] à data [6]).
NB 2: on se substitue à une vraie télécommande et il faut donc incrémenter le rolling code à chaque émission, ce qui contribue à désynchroniser la télécommande... donc prudence.

TODO: implémenter l'enregistrement en tant que nouvelle télécommande !!!

//
// (C)opyright yoyolb - 2014/08/05
// Version 0.1
//
// Tested with Arduino UNO and:
// - RX module RR3-433 (433.92 MHz) => port A1
// - TX module RT4-433 (433.92 MHz) => port A0
//
//
#define PORT_TX A0
#define PORT 2 // Arduino UNO = A1

// To store pulse length, in microseconds
volatile word pulse;

// Interrupt handler
#if defined(AVR_ATmega1280)
void ext_int_1(void) {
#else
ISR(ANALOG_COMP_vect) {
#endif
static word last;

// determine the pulse length in microseconds, for either polarity
pulse = micros() - last;
last += pulse;
}

void setup () {
Serial.begin(115200);
Serial.println("\n[SomfyDecoder]");

pinMode(PORT_TX, OUTPUT);
digitalWrite(PORT_TX, 0);

#if !defined(AVR_ATmega1280)
pinMode(PORT, INPUT); // use the AIO pin
digitalWrite(PORT, 1); // enable pull-up

// use analog comparator to switch at 1.1V bandgap transition
ACSR = _BV(ACBG) | _BV(ACI) | _BV(ACIE);

// set ADC mux to the proper port
ADCSRA &= ~ bit(ADEN);
ADCSRB |= bit(ACME);
ADMUX = PORT - 1;
#else
attachInterrupt(1, ext_int_1, CHANGE);

DDRE &= ~_BV(PE5);
PORTE &= ~_BV(PE5);
#endif
}

// Microseconds
const word k_tempo_wakeup_pulse = 9415;
const word k_tempo_wakeup_silence = 89565;
const word k_tempo_synchro_hw = 2416;
const word k_tempo_synchro_hw_min = 24160.7;
const word k_tempo_synchro_hw_max = 2416
1.3;
const word k_tempo_synchro_sw = 4550;
const word k_tempo_synchro_sw_min = 45500.7;
const word k_tempo_synchro_sw_max = 4550
1.3;
const word k_tempo_half_symbol = 604;
const word k_tempo_half_symbol_min = 6040.7;
const word k_tempo_half_symbol_max = 604
1.3;
const word k_tempo_symbol = 1208;
const word k_tempo_symbol_min = 12080.7;
const word k_tempo_symbol_max = 1208
1.3;
const word k_tempo_inter_frame_gap = 30415;

class CCodecSomfyRTS {
public:
enum t_status {
k_waiting_synchro,
k_receiving_data,
k_complete
};

public:
CCodecSomfyRTS();
t_status pulse(word p);
bool decode();
bool transmit(byte cmd, unsigned long rolling_code);

protected:
t_status _status;
byte _cpt_synchro_hw;
byte _cpt_bits;
byte _previous_bit;
bool _waiting_half_symbol;
byte _payload[7];
};

CCodecSomfyRTS::CCodecSomfyRTS()
: _status(k_waiting_synchro)
, _cpt_synchro_hw(0)
, _cpt_bits(0)
, _previous_bit(0)
, _waiting_half_symbol(false) {
for(int i=0; i<7; ++i) _payload = 0;
}
CCodecSomfyRTS::t_status CCodecSomfyRTS::pulse(word p) {

  • switch(_status) {*
  • case k_waiting_synchro:*
  • if (p > k_tempo_synchro_hw_min && p < k_tempo_synchro_hw_max) {*
  • ++_cpt_synchro_hw;*
  • }*
  • else if (p > k_tempo_synchro_sw_min && p < k_tempo_synchro_sw_max && _cpt_synchro_hw >= 4) {*
  • _cpt_bits = 0;*
  • _previous_bit = 0;*
  • _waiting_half_symbol = false;*
    for(int i=0; i<7; ++i) _payload = 0;
    * status = k_receiving_data;
    _
    } else {*

    * cpt_synchro_hw = 0;
    _
    }*

    * break;*

* case k_receiving_data:
if (p > k_tempo_symbol_min && p < k_tempo_symbol_max && !_waiting_half_symbol) {
_previous_bit = 1 - _previous_bit;
_payload[_cpt_bits/8] += _previous_bit << (7 - _cpt_bits%8);
++_cpt_bits;
} else if (p > k_tempo_half_symbol_min && p < k_tempo_half_symbol_max) {
if (_waiting_half_symbol) {
_waiting_half_symbol = false;
_payload[_cpt_bits/8] += _previous_bit << (7 - _cpt_bits%8);
++cpt_bits;
_
} else {*

* waiting_half_symbol = true;
_
}*

* } else {*
* _cpt_synchro_hw = 0;
status = k_waiting_synchro;
_
}*

* break;*

* default:*
* Serial.println("Internal error !");*
* break;*
* }*

* t_status retval = _status;*

* if (_status == k_receiving_data && cpt_bits == 56) {
retval = k_complete;
_
decode();*

* status = k_waiting_synchro;
_
}*

* return retval;*
}
bool CCodecSomfyRTS::decode() {
* // Dé-obfuscation*
* byte frame[7];*
* frame[0] = _payload[0];*
for(int i = 1; i < 7; ++i) frame = _payload ^ _payload[i-1];

_ //for(int i = 0; i < 7; ++i) Serial.print(frame*, HEX); Serial.print(" ");
//Serial.println("");*_

* // Verification du checksum*
* byte cksum = 0;*
for(int i = 0; i < 7; ++i) cksum = cksum ^ frame ^ (frame >> 4);
* cksum = cksum & 0x0F;*
* if (cksum != 0) Serial.println("Checksum incorrect !");*

* // Touche de controle*
* switch(frame[1] & 0xF0) {*
* case 0x10: Serial.println("My"); break;*
* case 0x20: Serial.println("Up"); break;*
* case 0x40: Serial.println("Down"); break;*
* case 0x80: Serial.println("Prog"); break;*
* default: Serial.println("???"); break;*
* }*

* // Rolling code*
* unsigned long rolling_code = (frame[2] << 8) + frame[3];
Serial.print("Rolling code: "); Serial.println(rolling_code);*

* // Adresse*
* unsigned long address = ((unsigned long)frame[4] << 16) + (frame[5] << 8) + frame[6];*
* Serial.print("Adresse: "); Serial.println(address, HEX);*
}
bool CCodecSomfyRTS::transmit(byte cmd, unsigned long rolling_code) {
* // Construction de la trame claire*
* byte data[7];*
* data[0] = 0xA0;*
* data[1] = cmd << 4;*
* data[2] = (rolling_code & 0xFF00) >> 8;
data[3] = rolling_code & 0x00FF;
_ data[4] = 0x ; // Address*
* data[5] = 0x ; // Address*
* data[6] = 0x ; // Address*_

* // Calcul du checksum*
* byte cksum = 0;*
for(int i = 0; i < 7; ++i) cksum = cksum ^ data ^ (data >> 4);
* data[1] = data[1] + (cksum & 0x0F);*

* // Obsufscation*
for(int i = 1; i < 7; ++i) data = data ^ data[i-1];
* // Emission wakeup, synchro hardware et software*
* digitalWrite(PORT_TX, 1);
delayMicroseconds(k_tempo_wakeup_pulse);
digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_wakeup_silence);*

* for(int i=0; i<7; ++i) {*
* digitalWrite(PORT_TX, 1);
delayMicroseconds(k_tempo_synchro_hw);
digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_synchro_hw);
_ }*_

* digitalWrite(PORT_TX, 1);
delayMicroseconds(k_tempo_synchro_sw);
digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_half_symbol);*

* // Emission des donnees*
* for(int i=0; i<56;++i) {*
* byte bit_to_transmit = (data[i/8] >> (7 - i%8)) & 0x01;
if (bit_to_transmit == 0) {
digitalWrite(PORT_TX, 1);
delayMicroseconds(k_tempo_half_symbol);
digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_half_symbol);
_ }
else*

* {_
digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_half_symbol);
digitalWrite(PORT_TX, 1);
delayMicroseconds(k_tempo_half_symbol);
_ }
}*_

* digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_inter_frame_gap);
_}
void loop() {
static CCodecSomfyRTS codecSomfyRTS;
static word cpt = 0;*_

* cli();*
* word p = pulse;*
* pulse = 0;*
* sei();*
// codecSomfyRTS.transmit(0x4, XXXX);
* if (p != 0) {*
* codecSomfyRTS.pulse(p);*
* }*
}

Cool :wink: un grand merci à toi ^^ Je test ça demain

Bonjour,

Je reposte mon code en utilisant une pièce jointe car ma précédente tentative n'a pas été une réussite. En effet, le copier-coller vers le forum a altéré le code (suppression de , insertion de smileys parasites...).
Le code en PJ devrait être correct cette fois !
Lionel.
somfy_.ino (6.81 KB)

D'abord, Merci pour ce travail! je pense qu'il va servir à pas mal de monde qui attendait une solution low-cost pour piloter du SOMFY!

j'ai sauté sur l'occaz et acheté un RR3-433 et un RT40-433 et testé ca sur un Arduino uno, malheureusement... impossible de lire les trames émises par mes télécommandes...

==> il y a une chose que je ne comprend pas dans le setup :
"ADMUX = PORT - 1;", soit la valeur décimale 14 (port étant initialisé à 15 (A1))

d'après les références que j'ai trouvé sur le contenu de ADMUX
bit 7 = REFS1
bit 6 = REFS0
bit 5 = ADLAR
bit 4 = -
bit 3 = MUX3
bit 2 = MUX2
bit 1 = MUX1
bit 0 = MUX0
==> avec REFS1 = 1 et REFS0 = 1 pour une référence à 1.1V

Bonsoir,

Hmmm... dans le code que j'ai fourni PORT est positionné à 2 (#define PORT 2) en début de fichier.

Cela correspond à la PIN A1 de ma carte Arduino UNO (mais PORT doit bien être positionné à 2 pour cela).

Lionel.

Hi
I am following up this topic and try to test the sketch given by yoyolb and not successful. Maybe I don't know how to test it.
What I did was that I conncet RX pin to Uno A1 (which is digital 15), monitor from serial monitor. Nothing happy.

Appreciate it if someone who tested successfully share the procedure and show how to use it.

Regards
WiN