Protocole Somfy (Reverse engi RTS)

Bonjour yoyolb ;)

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 :D

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 ;) 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

Bonsoir à tous,

Un grand bravo et merci à yoyolb de partager son code.

J'ai réussi à écouter mes télécommande telis (un peu galère les branchement du RR3... 3 masses, 4 VCC, 1 fil data (pin 14) sur A0). J'ai extrait ce schema de branchement des datasheets présente sur le site du fabricant : http://www.telecontrolli.com/risorse/download1/

Par contre, pour l'envoi de trame, je n'y suis pas arrivé (bien que les branchement pour le RT4 / RT40 soit plus simples). Peux-tu me dire si tu as commenté certaines lignes lors de tests qui avait l'air d'usurper le rolling d'une télécommande ?

Encore merci à tous.

Bonsoir,

Merci pour ce super boulot, j'arrive également à décoder mes télécommande, mais la commande transmit ne semble pas fonctionner.

Pour être sûr :

Si je recois (Ce ne sont pas les miennes, j'ai modifié les valeur): My Rolling code: 1000 Adresse: 4A5B5C

Je dois mettre dans le programme ? data[4] = 0x4A; // Address: USE YOUR OWN ADDRESS !!! data[5] = 0x5B; // Address: USE YOUR OWN ADDRESS !!! data[6] = 0x5C; // Address: USE YOUR OWN ADDRESS !!!

Et lancer la commande (une seule fois, sur le click d'un poussoir) : int g_rolling = 1001; codecSomfyRTS.transmit(0x4, g_rolling); //0x4 pour descendre

Sommes nous d'accord? Chez moi cela ne fonctionne pas.

Et encore merci pour ce super boulot.

Hello,

wow, I’m surprised about your work!

But its really hard to understand the “bing” translation from francais to german.

If I understood it right , you use the analog ports of arduino one an not the digital?

I have an arduino uno and 433Mhz Moduls to send and receive.

But I didn’t understand where I shout connect it to the arduino which port?
And also I didn’t understand realy what I have to do after starting arduino?

May I ask you to explain it in English for me please?

thank you very much.

Best regards
Jens

I just tried! WOW!!!!

Is that only to read or can I send the signal also ? If yes, how?

than you very much!

Jens

Halo,

AingTii: Hello,

wow, I'm surprised about your work!

But its really hard to understand the "bing" translation from francais to german.

If I understood it right , you use the analog ports of arduino one an not the digital?

I have an arduino uno and 433Mhz Moduls to send and receive.

But I didn't understand where I shout connect it to the arduino which port? And also I didn't understand realy what I have to do after starting arduino?

May I ask you to explain it in English for me please?

thank you very much.

Best regards Jens

Du kanst mir Fragen stellen in Deutscher Sprache über Private Mail MfG

Bonsoir, Comment faites vous pour transmettre un code ? @

Did anyone ever had a successful transmit? Which RF-Transmitters do you use?

Receiving is working here...but Registration ain't. :(

Hey guys,

thank you yoyolb, very nice work.

Receiving works well and I'm also able to transmit something. I made a testbuild with 2 Arduinos including yoyolb's sketches. One to transmit my own Code and the other one to recive it. Both outputs of the console (original remote / fake) are equal, but I wasn't able to move my blinds.

I added my Adress equal to my recived Adresse: XXYYZZ

  • data[4] = 0xXX;
  • data[5] = 0xYY;
  • data[6] = 0xZZ; And during a pressed Button I run:

codecSomfyRTS.transmit(0x4,410); (Down?/~410 recived rolling_code)

On the other hand I tried the Copy/Paste way somfy described here: SOMFY: Copy and Paste PART 1: Adding A New Remote

I modified the "Adresse", the "rolling_code" and used the "0x8" (Prog.) command. The result is no Up/Down movement of the blinds to conform the new (fake) remote.

Is it possible that yoyolb's code is not able to simulate a pressed button with no increasing rolling_code?

Nevertheless the first way must also work ?!? Any ideas?

BR

Please continue in french or open a topic in the english section...

fine!

Hé les gars,

merci yoyolb, très beau travail.

Réception fonctionne bien et je suis aussi capable de transmettre quelque chose. Je ai fait une TestBuild avec 2 Arduinos y compris les croquis de yoyolb. Un de transmettre ma propre Code et l'autre à recive. Les deux sorties de la console (télécommande d'origine / faux) sont égaux, mais je ne étais pas capable de se déplacer mes stores.

Je ai ajouté mon adresse égale à mon Adresse recived: xxyyzz

données [4] = 0XXX; données [5] = 0xYY; données [6] = 0xZZ;

Et lors d'une touche enfoncée je lance:

codecSomfyRTS.transmit (0x4,410); (Down? / ~ 410 recived rolling_code)

D'autre part je ai essayé le Copier / Coller façon Somfy décrit ici: SOMFY: Copier et Coller PARTIE 1: Ajout d'une nouvelle télécommande

Je ai modifié la commande (Prog.) "Adresse", le "rolling_code" et utilisé le "0x8". Le résultat ne est pas Up / Down mouvement des stores pour se conformer au nouveau (faux) à distance.

Est-il possible que le code de yoyolb ne est pas en mesure de simuler un bouton enfoncé sans rolling_code croissante?

Néanmoins, la première façon doit également travailler?!? Toutes les idées?

BR

Bonjour, Je bute sur le même souci: l'émission d'une commande n'est pas comprise par le récepteur Somfy. Mes essais: - platine Arduino 1 + emetteur 433 Mhz + sketch somfy_.ino dédié émission - platine Arduino 2 + récepteur 433 Mhz + sketch somfy_.ino dédié réception - télécommande RTS - les sketchs ont été modifiés pour afficher les codes à différents niveaux: -- en émission: avant calcul checksum, aprés, et après obfuscation (donc ce qui est transmis à l'émetteur) -- en réception: code reçu du récepteur avant dé-obfuscation, et après dé-obfuscation. Modifs également apportées sur les calculs de chksum et obfuscation.

Essais: 1- Appui sur touche Down de la télécommande Arduino2 affiche code reçu par le récepteur=AFEDFCC4273C77, puis aprés dé-obf. AF421138E31B4B c'est-à-dire Down/RC=4408/Adr=E31B4B 2- Sur Arduino 1, émission avec Up/RC=4409/ Adr idem AF201139E31B4B = trame avant chcksum AF251139E31B4B = après chksum AF8A9BA2415A11 = après obfuscation 3- Sur Arduino 2, réception de AF8A9BA2415A11 = avant dé-obf. AF251139E31B4B = après dé-obf.

On constate que les trames sont bien identiques avant et après réception et par rapport à la télécommande. Mais .... pas d'action sur le volet, qui est à 3m de l'émetteur ! Idées à creuser: - du côté des signaux de wake up/ synchro hw/ synchro sw ?? - changer le type d'émetteur (précision sur la fréquence ?)

Avis ?