Tchibo Wetterstation 433 MHz - Dekodierung mal ganz einfach

Hallo,
nachdem ich mir bei eB** einige günstige 433MHz Sender und Empfänger beschafft hatte, wollte ich natürlich was sinnvolles damit anfangen.
Zu Tchibo Wetterstationen gab es ja schon einige Beiträge und die Autoren haben ja teilweise graue Haare bekommen, wenn’s um die Dekodierung des Datenstroms ging.
Dass es auch anders sein kann, möchte ich mit diesem Beitrag zeigen.
Ich habe bei mir eine Tchibo Wetterstation im Einsatz, die schon einige Jahre auf dem Buckel hat. Die Artikelnummer ist TCM 218943. Der Außensensor sendet seine Daten auf 433 MHz. Beim Test der besagten Receiver hatte ich schon den Datenstrom des Außensensors “gesehen” und wollte mir den dann mal näher ansehen.
Als ersten Schritt habe ich das Signal des Receivers über einen 10k Widerstand und einen 1uF Kondensator auf den Mikrofoneingang der Soundkarte gelegt und mit Audacity aufgezeichnet (s. Screenshot). Da immer 36 Pausen zwischen kurzen HIGH-Pulsen übertragen werden, habe ich angenommen, dass kurze Pause eine “1” sind und lange Pause eine “0”. Um das Ergebnis vorwegzunehmen, es war genau umgekehrt.
Nachdem ich dann einige Datenströme mit unterschiedlichen Temperatur und Feuchtewerten aufgezeichnet hatte, fand ich schnell raus, welche Nibbles für Temperatur und welche für Feuchte stehen.
Die letzten 12 Bits des Datenstroms stehen für die Temperatur und die 8 Bit davor für die Feuchte. Bei negativen Temperaturen sind die ersten 4 Bits der Temperatur “1111”.
Die ersten 8 Bits stehen vermutlich für die Kennung des Außensensors.
Hier ein Beispiel:
11101011 00000000 00111101 000000010001
Kennung Feuchte Temperatur
Die Werte sind einfach aus dem Byte herzuleiten, also hier
Feuchte 00111101 = 16 (also 16%)
Temperatur 0000 00010001 = 17 (also +1.7°)

Natürlich wär ich hier im falschen Forum, wenn ich das Signal nicht auch per Software verarbeiten wollte, hier der Code.
Der Ausgang des Receivers liegt auf dem Interrupt 0, also Digital 2. Der Interrupt wird durch die fallenden Flanken getriggert und die Zeit zwischen den Flanken wird ausgewertet.
Das Programm ist recht überschaubar und kann auch leicht auf andere Pulslängen adaptiert werden. Für Anregungen, wie man das besser programmieren kann, bin ich natürlich dankbar.

#define PINA 2
#define INTERRUPT 0  // that is, pin 2
volatile unsigned long EdgeTime;   // zur Speicherung der Zeit
unsigned long LastEdgeTime=0;
unsigned long DiffEdgeTime=0;
unsigned long LastMillis;
unsigned int Counter;
unsigned long Sequenz, OldSequenz;
unsigned int BitCount, ByteCount, SeqCounter;
volatile boolean BitSet;

// Interrupt Service Routine for a falling edge
void isr ()
{
  if (!BitSet) {
    EdgeTime=micros();
    BitSet=true;
  }
}  // end of isr

void setup ()
{
  attachInterrupt (INTERRUPT, isr, FALLING);   // interrupt 0 is pin 2
  Serial.begin(115200);
}

void loop ()
{
  while(millis()-LastMillis < 5000)  {    // jede 5 Sekunden Status
    if (BitSet) {
      DiffEdgeTime = EdgeTime-LastEdgeTime;    
      if (DiffEdgeTime > 800)  {        // alles kleiner ist Fehler
        if (DiffEdgeTime>8000 && DiffEdgeTime<8500)  {   // Synchronisationpuls
           Counter=0;
           Sequenz=0;
        }
        else if (DiffEdgeTime>1800  && DiffEdgeTime<2300) {
          Sequenz <<= 1;
          Sequenz |= 1;               // eine 1 von rechts rein
          Counter++;
        }
        else if (DiffEdgeTime>900 && DiffEdgeTime<1300) {
          Sequenz <<= 1;                  // eine 0 von rechts rein
          Counter++;
        }
       if (Counter==8 && Sequenz!= B11111011) {  // Sensor Kennung
           Counter=0;
           Sequenz=0;
       }
       if (Counter==36) {
         if (OldSequenz==Sequenz) {    
           SeqCounter++;  // Anzahl gleicher Sequenzen in Folge
         }
         else {
           SeqCounter=1;
         }
         OldSequenz=Sequenz;
         Serial.print("SeqC ");
         Serial.print(SeqCounter);        
         Serial.print("  ");
         Serial.print(Sequenz,BIN);
         Serial.print("  ");
         if (Sequenz& 0x0F00) {   // negative Werte
           Serial.print("-");
           Serial.print(Sequenz & 0xFF);
         }
         Serial.print(Sequenz & 0xFF);   // Temp
         Serial.print("  ");
         Sequenz >>= 12;
         Serial.println(Sequenz & 0xFF);  // Feuchte
         Counter=0;
         Sequenz=0;
       }
      }
      LastEdgeTime=EdgeTime;
      BitSet=false;
    }  
  }
  LastMillis=millis();
  Serial.println("*");
}

Gruß
Reinhard

Wahnsinn! Danke für den lehrreichen Post! Werde mir mal so einen "Sender" besorgen und schauen ob ich die Daten auch dem Netzwerk zur Verfügung stellen kann.

Feuchte 00111101 = 16 (also 16%)

Hab ich nicht verstanden, ( meinst du 61 % ?)
sonst aber : Toll !!!

michael_x:

Feuchte 00111101 = 16 (also 16%)

Hab ich nicht verstanden, ( meinst du 61 % ?)
sonst aber : Toll !!!

Ja, danke - gut aufgepasst. Es muss natürlich 61 heißen.

Hallo, jetzt haben wir negative Temperaturen und dadurch habe ich einen Fehler in der Ausgabe gemerkt. Ich poste mal die entscheidenden Zeilen, die geändert werden müssen.

         if (Sequenz& 0x0F00) {   // negative Werte
           Serial.print(int((Sequenz & 0xFFF)|0xF000));
         }
         else {
         Serial.print(Sequenz & 0xFF);   // Temp
         }

Die Umwandlung in Integer hätte man sicher auch eleganter lösen können, aber ich wollte jetzt nicht zuviel ändern.

Die letzten 12 Bits des Datenstroms stehen für die Temperatur ... Bei negativen Temperaturen sind die ersten 4 Bits der Temperatur "1111".

Ich frage mich warum 4 bit für das Vorzeichen verschwendet werden sollten. Bist du sicher, dass es nicht einfach eine vorzeichenbehaftete 12 bit - Zahl ist ? Der Wertebereich wäre dann deutlich größer: statt +-25.6 wären -204.8 ... 204.7 °C übertragbar. Das ist natürlich -besonders im negativen Bereich- schwer zu testen. Aber, ich fürchte, dein Code zeigt noch einen Fehler im nächsten Sommer, oder wenn du einen Fön zum Testen über 25 °C nimmst.

int16_t temp = Sequenz & 0x0FFF ; 
if (temp & 0x800) temp |= 0xF000; // negativ: Vorzeichenbit setzen
Serial.print (temp);

P.S. Erstaunlich, dass so viel Logik ( Skalierung ) schon im Aussenfühler-Sender steckt. Ist nirgends eine Celsius/Fahrenheit Umschaltung vorgesehen ?

michael_x: Aber, ich fürchte, dein Code zeigt noch einen Fehler im nächsten Sommer, oder wenn du einen Fön zum Testen über 25 °C nimmst.

Einmal wurde der Code bereits vom Thread-Starter selbst korrigiert, eine weitere Ungereimtheit bei sommerlichen Temperaturen von michael_x aufgedeckt.

Soviel also zum Thema "mal ganz einfach". ;-)

Wie lauten doch noch die ersten drei Murphy-Gesetze: 1. Nichts ist so einfach wie es scheint. 2. Alles dauert länger als Du denkst. 3. Wenn irgendwas schiefgehen kann, wird es auch schiefgehen.

Happy decoding!

BTW: Lidl hat diese Woche ein "AURIOL Funk-Wetterstationsset" als Sonderposten für 49,95 mit Außensensoren auch für Regenmenge und Windgeschwindigkeit. Die Funksensoren scheinen auch auf 433 MHz zu laufen. Leider ohne Datenspeicher, ohne PC-Auswertemöglichkeit und erst Recht ohne Internetanschluss. Ich überlege, ob ich mir eine solche Wetterstation holen und mir selbst zu Weihnachten schenken soll, um mit einem Arduino, einem Ethernet-Shield und einem China-433MHz-Receiver die Decodierung und Umrüstung zur "PC-Wetterstation mit Internetanschluss" probieren soll.

Hallo michael_x
du hast vollkommen Recht. Die Temperatur ist eine vorzeichenbehaftete 12Bit Zahl, irgendwie war ich wohl irritiert wegen der 12 Bit.
Dein Code Schnipsel ist perfekt.
Inzwischen habe ich weitere Erkenntnisse sammeln können, ich fasse mal alles zusammen.
Beispiel für die 36 Bit:
01100010 10010000 00100011 000011011101
Bit 1 9 17 25 36
Bit 1-8 ist Sensor-Kennung, die sich zufällig bei jedem Batteriewechsel ändert
Bit 9 Low Bat Kennzeichnung
Bit 12 auf der Rückseite des Sensors wurde der TX Button gedrückt, damit registriert die Basisstation diesen Sensor als neuen Sensor. Bit ist für eine Sendung=28x36 Bit gesetzt
Bit 17-24 Feuchte
Bit 25-36 Temperatur als vorzeichenbehaftete 12Bit Zahl

Der Sensor hat die Möglichkeit der Umschaltung von °C nach Fahrenheit. Das verändert aber nur die Anzeige auf dem Display des Sensors, die Datenübertragung ist immer in °C
Im nachfolgenden Programm habe ich den Test der Sensorkennung entfernt und die Ausgabe ein wenig besser formatiert. Bei der Darstellung in Binärform werden die führenden Nullen natürlich nicht mit ausgegeben. So sieht dann die Ausgabe aus:

*
*
*
SeqC 1  100110010000000  100011  11011011  219  35
SeqC 2  100110010000000  100011  11011011  219  35
SeqC 3  100110010000000  100011  11011011  219  35
SeqC 4  100110010000000  100011  11011011  219  35
SeqC 5  100110010000000  100011  11011011  219  35
SeqC 6  100110010000000  100011  11011011  219  35
SeqC 7  100110010000000  100011  11011011  219  35
SeqC 8  100110010000000  100011  11011011  219  35
SeqC 9  100110010000000  100011  11011011  219  35
SeqC 10  100110010000000  100011  11011011  219  35
SeqC 11  100110010000000  100011  11011011  219  35
SeqC 12  100110010000000  100011  11011011  219  35
SeqC 13  100110010000000  100011  11011011  219  35
SeqC 14  100110010000000  100011  11011011  219  35
SeqC 15  100110010000000  100011  11011011  219  35
SeqC 16  100110010000000  100011  11011011  219  35
SeqC 17  100110010000000  100011  11011011  219  35
SeqC 18  100110010000000  100011  11011011  219  35
SeqC 19  100110010000000  100011  11011011  219  35
SeqC 20  100110010000000  100011  11011011  219  35
SeqC 21  100110010000000  100011  11011011  219  35
SeqC 22  100110010000000  100011  11011011  219  35
SeqC 23  100110010000000  100011  11011011  219  35
SeqC 24  100110010000000  100011  11011011  219  35
SeqC 25  100110010000000  100011  11011011  219  35
SeqC 26  100110010000000  100011  11011011  219  35
SeqC 27  100110010000000  100011  11011011  219  35
SeqC 28  100110010000000  100011  11011011  219  35
*
SeqC 1  1110110110010  10010000  11000000  192  144
*
*

In diesem Beispiel wurden die 28 Datensätze alle richtig erkannt. Danach wurde einmal ein Datensatz gefunden, der sich nicht wiederholte und damit vom Programm als fehlerhaft verworfen wird. In den meisten Fällen werden 26-28 aufeinander folgende Datensätze erkannt. Vielleicht wird das schlechter, wenn die Entfernung zum Sensor größer wird.
Hier nochmal der veränderte Code

#define PINA 2
#define INTERRUPT 0  // that is, pin 2
volatile unsigned long EdgeTime;   // zur Speicherung der Zeit
unsigned long LastEdgeTime=0;
unsigned long DiffEdgeTime=0;
unsigned long LastMillis;
unsigned int Counter;
unsigned long OldSequenz;
long Sequenz, Temp;
unsigned int BitCount, ByteCount, SeqCounter, Kennung;
volatile boolean BitSet;

// Interrupt Service Routine for a falling edge
void isr ()
{
  if (!BitSet) {
    EdgeTime=micros();
    BitSet=true;
  }
}  // end of isr

void setup ()
{
  attachInterrupt (INTERRUPT, isr, FALLING);   // interrupt 0 is pin 2
  Serial.begin(115200);
}

void loop ()
{
  while(millis()-LastMillis < 5000)  {    // jede 5 Sekunden Status
    if (BitSet) {
      DiffEdgeTime = EdgeTime-LastEdgeTime;    
      if (DiffEdgeTime > 800)  {        // alles kleiner ist Fehler
        if (DiffEdgeTime>8000 && DiffEdgeTime<8500)  {   // Synchronisationpuls
           Counter=0;
           Sequenz=0;
        }
        else if (DiffEdgeTime>1800  && DiffEdgeTime<2300) {
          Sequenz <<= 1;
          Sequenz |= 1;               // eine 1 von rechts rein
          Counter++;
        }
        else if (DiffEdgeTime>900 && DiffEdgeTime<1300) {
          Sequenz <<= 1;                  // eine 0 von rechts rein
          Counter++;
        }
/*       if (Counter==8 && Sequenz!= B11000101) {  // Sensor Kennung
           Counter=0;
           Sequenz=0;
       }*/
       if (Counter==16) Kennung=Sequenz;    // SensorKennung
       if (Counter==36) {
         if (OldSequenz==Sequenz) {    
           SeqCounter++;  // Anzahl gleicher Sequenzen in Folge
         }
         else {
           SeqCounter=1;
         }
         OldSequenz=Sequenz;
         Serial.print("SeqC ");
         Serial.print(SeqCounter);        
         Serial.print("  ");
         Serial.print(Kennung,BIN);
         Serial.print("  ");
         Serial.print((Sequenz&0xFF000)>>12,BIN);
         Serial.print("  ");
         Serial.print((Sequenz&0x00FFF),BIN);
         Serial.print("  ");
         Temp = Sequenz & 0x0FFF;
         if (Sequenz & 0x0800) {   // negative Werte
           Temp |= 0xF000;     // Vorzeichen zur Ausgabe setzen für 16Bit INT
         }
         Serial.print(Temp);
         Serial.print("  ");
         Sequenz >>= 12;
         Serial.println(Sequenz & 0xFF);  // Feuchte
         Counter=0;
         Sequenz=0;
       }
      }
      LastEdgeTime=EdgeTime;
      BitSet=false;
    }  
  }
  LastMillis=millis();
  Serial.println("*");
}

Dieses Programm ist ja gedacht zum Debuggen. Der nächste Schritt wird jetzt sein, Temperatur und Feuchte auf LCD anzuzeigen oder auf eine SD Karte zu loggen.
Leider scheint dieser Sensor nicht mehr erhältlich zu sein. Ich häng mal ein Foto an.
Nachtrag: Ich hab gerade mal den Sensor in den Gefrierschrank gelegt. Wenn man Glück hat kommen 4 Datensätze in Folge ohne Fehler an.

jurs:
Soviel also zum Thema “mal ganz einfach”.
:wink:

Wie lauten doch noch die ersten drei Murphy-Gesetze:

  1. Nichts ist so einfach wie es scheint.
  2. Alles dauert länger als Du denkst.
  3. Wenn irgendwas schiefgehen kann, wird es auch schiefgehen.

Na ja, im Vergleich zu anderen Dokodierversuchen, wo hier im Forum gemeinsam lange orakelt wurde, war das doch wirklich einfach.
Und ohne Murphy ist alles hur halb so lustig.
Bin mal gespannt, ob sich die Lidl Station dekodieren lässt.
Gruss

Danke Murphy!
Statt

long Sequenz, Temp;

muss es richtig heissen

long Sequenz;
int Temp;

Wenn schon, tut auch nichts zur Sache, aber schöner wäre:

[b]unsigned [/b] long Sequenz;

Übrigens, ich finde, dank deines sehr guten Ansatzes, war die Dekodierung wirklich "mal ganz einfach". Glückwunsch ernie-bernie

Hallo,

das sind ja recht gute Anregungen. Ich hab heute erstmal mit dem Audacity das Bild der Aldi Außensensoren aufgenommen. Das ist ja ein Problem, was noch ungelöst bei mir rumliegt. Die Sensoren senden dreimal hintereinander gleiche Datenpakete, da müssten die letzten beiden mit sicherheit dekodierbar sein. Falls ich Erfolge habe, melde ich mich, wenn nicht, auch.

Gruss Kalli

Kalli: das sind ja recht gute Anregungen. Ich hab heute erstmal mit dem Audacity das Bild der Aldi Außensensoren aufgenommen. Das ist ja ein Problem, was noch ungelöst bei mir rumliegt. Die Sensoren senden dreimal hintereinander gleiche Datenpakete, da müssten die letzten beiden mit sicherheit dekodierbar sein.

Ja, sicherlich. Mit entsprechend Gehirnschmalz dürfte es machbar sein, wenn man die Bits erstmal auslesen kann.

"Kryptographisch verschlüsselt" sind die Bits in den Funkdaten wohl nicht, sondern nur "codiert".

Ich habe mich auch noch mal etwas näher informiert, und zumindest die ganz einfachen 433-MHz-Module der billigsten Funk-Thermometer und Funk-Wetterstationen scheinen alle nach demselben Grundschema mit ASK/OOK (Amplitudenmoduliertes Signal mit ON/OFF-Tastung) zu arbeiten. Und dabei immer dasselbe Sendeschema zu haben, dass zu LOW Pulsen verschiedener Länge am Empfänger führt. Es gibt quasi Bits mit drei verschiedenen Längen:

  1. Start-Bit ==> Ein besonders langer StartPuls zu Beginn eines Datenpakets
  2. Daten 1-Bit ==> Ein deutlich kürzerer Impuls (ca. 1/4 der Länge eines Start-Bit)
  3. Daten 0-Bit ==> Ein nochmals kürzerer Impuls (ca. halbe Länge eines 1-Bit)

Und das nicht nur beim Tchibo-Funkthermometer, sondern bei fast allen billigen 433-MHz Funkthermometern und Funkwetterstationen.

Bei einem Controller-Takt von 16 MHz und einer Datenbitrate von höchstens 10 KBit/s frage ich mich, ob man sich die Auswertung von Sendeimpulsen am Oszilloskop oder per Soundkartenaufnahme nicht sparen kann, wenn man einfach einen Arduino-Sketch schreibt, zur Analyse und Vorab-Auswertung, der einem einfach Daten ausgibt wie:

  • Datenpaket erkannt
  • Startbitlänge xxxx Mikrosekunden
  • Anzahl der Datenbits im Paket: xy
  • Länge eines 0-Bits: xxx Mikrosekunden
  • Länge eines 1-Bits: yyy Mikrosekunden
  • Erkannte Bitfolge: 00100010100111...

Wenn man von so einer Vorauswertung per Arduino-Sketch dann schon ohne viel Aufwand die richtigen Längen für Startbit, 0-Bit, 1-Bit und die Anzahl der Bits in den Datenpaketen automatisch bekommen hat, kann man gleich mit einem speziellen Auswerteprogramm zur Auswertung der Bits weitermachen.

Solche ein bequemes Wettersensor-Vorauswertungsprogramm gibt es wohl noch nicht, wenn zum Dekodieren üblicherweise mit Bildern vom Oszilloskop oder von einem Soundkarten-Aufnahmeprogramm angefangen wird, oder?

Hallo jurs, wenn du mein Programm in diesem Beitrag auf die Biterkennung reduzierst, macht es genau das, was du beschrieben hast. Worauf stützt du deine Darstellung, dass die Kodierung immer so läuft bei den billigen Stationen? Ich finde den ersten Einstieg über die Soundkarte gar nicht so schlecht, da weiß man zumindest schon mal, was man zu erwarten hat. Die Zeiten kann man dann sehr einfach über ein Programm messen, dass eigentlich für IR Fernbedienungen gedacht ist. http://playground.arduino.cc/Code/InfraredReceivers. Einfach statt des IR-Empfänger einen 433 MHz Empfänger anschließen. Wenn man die Zeiten dann in mein Programm nimmt, ist man schon fast am Ziel. Jetzt muss man nur noch die Bits zuordnen.

@Kalli: stell doch mal einen Screenshot von deiner Audacity Messung an deinem Sensor hier rein.

erni-berni: Worauf stützt du deine Darstellung, dass die Kodierung immer so läuft bei den billigen Stationen?

Immer wohl nicht. Aber ganz, ganz oft.

Ich habe hier im Haus nun schon drei 433MHz-Funksensoren rausgekramt, die alle nach demselben Schema senden: - ein gaaaanz langes Startbit, danach kommt ein Datenpaket aus mehreren kürzeren Bits, und zwar - 1-Bits mit bestimmter Länge (deutlich kürzer als das Start-Bit) und - meist halb so langen 0-Bits

Allerdings gibt es Unterschiede zwischen den Sensoren: Verschiedene Startbitlänge, verschiedene 1-Bit Länge, verschiedene 0-Bit Länge, und verschieden viele Bits in einem Datenpaket.

Und wenn man nur mit Try-and-Error herumprobiert, ist das eine mühsame Angelegenheit, die Startbitlänge, 1-Bit-Länge, 0-Bit-Länge und Anzahl der Datenbits im Paket herauszubekommen. Dafür hätte ich gerne einen Sketch, der das automatisch ermittelt und rauswirft, was so an Funk herumschwirrt.

erni-berni: wenn du mein Programm in diesem Beitrag auf die Biterkennung reduzierst, macht es genau das, was du beschrieben hast.

Nicht so ganz, Deinem Programm muß ich ja wenigstens ungefähr die Startbitlänge, 0-Bit Länge und 1-Bit Länge vorgeben, sonst wird das mit der Biterkennung nichts. Das sind ja Werte, in denen sich die Sensoren gerade unterscheiden. Und die Timings der Bits würde ich gerne direkt, ohne Umweg über Soundkarte oder Oszilloskop ermitteln, nur mit dem Arduino.

erni-berni: Ich finde den ersten Einstieg über die Soundkarte gar nicht so schlecht, da weiß man zumindest schon mal, was man zu erwarten hat.

Tja, da muss man dann wohl zu Anfang mit loslegen, wenn man seinen Sensor mit "bekannten" Timingwerten anderer Sensoren (Tchibo und Co.) nicht im Datenstrom identifizieren kann. Diese billigen 433-MHz Empfänger empfangen ja immer irgend etwas, selbst wenn sie nichts empfangen. In den Empfangspausen drehen die intern immer die Empfangsempfindlichkeit so weit auf, bis sie Rauschen empfangen - und dann ist das Rauschen auf dem Datenausgang. Und man selbst steht vor dem Problem zu erkennen: Was ist Rauschen - was sind die Nutzdaten eines Funk-Sensors?

Ich habe das oben erwähnte Programm mal für den Zweck der Messung der Implulse angepasst.

// Das ursprüngliche Programm stammte von
/*
 *  Author..... Walter Anderson 
 *  E-mail..... wandrson@walteranderson.us 
 *  
 *  Source: http://playground.arduino.cc/Code/InfraredReceivers
 */ 
#include <avr/interrupt.h>
#include <avr/io.h>

#define TIMER_RESET  TCNT1 = 0
#define SAMPLE_SIZE  128

int IRpin = 2;
unsigned int TimerValue[SAMPLE_SIZE];
char direction[SAMPLE_SIZE];
byte change_count;
long time;

void setup() {
  Serial.begin(115200);
  Serial.println("Analyze IR Remote");
  TCCR1A = 0x00;          // COM1A1=0, COM1A0=0 => Disconnect Pin OC1 from Timer/Counter 1 -- PWM11=0,PWM10=0 => PWM Operation disabled
  // ICNC1=0 => Capture Noise Canceler disabled -- ICES1=0 => Input Capture Edge Select (not used) -- CTC1=0 => Clear Timer/Counter 1 on Compare/Match
  // CS12=0 CS11=1 CS10=1 => Set prescaler to clock/64
  TCCR1B = 0x03;          // 16MHz clock with prescaler means TCNT1 increments every 4uS
  // ICIE1=0 => Timer/Counter 1, Input Capture Interrupt Enable -- OCIE1A=0 => Output Compare A Match Interrupt Enable -- OCIE1B=0 => Output Compare B Match Interrupt Enable
  // TOIE1=0 => Timer 1 Overflow Interrupt Enable
  TIMSK1 = 0x00;          
  pinMode(IRpin, INPUT);
}

void loop()
{
  Serial.println("Waiting...");
  change_count = 0;
  while(digitalRead(IRpin) == LOW) {}                                 
  TIMER_RESET;
  TimerValue[change_count] = TCNT1;
  direction[change_count++] = '1';
  while (change_count < SAMPLE_SIZE) {
    if (direction[change_count-1] == '0') {
      while(digitalRead(IRpin) == LOW) {}
      TimerValue[change_count] = TCNT1;
      direction[change_count++] = '1';
  TIMER_RESET;
    } else {
      while(digitalRead(IRpin) == HIGH) {}
      TimerValue[change_count] = TCNT1;
      direction[change_count++] = '0';
  TIMER_RESET;
    }
  }
  Serial.println("Bit stream detected!");
  change_count = 1;
  time = (long) TimerValue[change_count] * 4;
  while (change_count < SAMPLE_SIZE) {
    time = (long) TimerValue[change_count] * 4;
    Serial.print(time);
    Serial.print("\t");
    Serial.println(direction[change_count-1]);    
    change_count++;
  }
  Serial.println("Bit stream end!");
  delay(2000);
}

Wenn man Glück hat und einen gültigen Datenstrom einfangen kann, sieht das ganz gut aus. Allerdings kommt wie bereits schon gesagt auch viel Müll an. Hier mal ein gutes Beispiel.

Analyze IR Remote
Waiting...
Bit stream detected!
28	1
189448	0
12	1
240792	0
4	1
176688	0
12	1
122560	0
164	1
8112	0
152	1
1060	0
148	1
1060	0
148	1
2084	0
152	1
1052	0
156	1
1060	0
148	1
2084	0
152	1
1064	0
144	1
1064	0
148	1
1060	0
148	1
1068	0
136	1
1064	0
152	1
1056	0
156	1
1064	0
136	1
1064	0
140	1
1068	0
136	1
1072	0
144	1
1064	0
148	1
2096	0
144	1
1064	0
140	1
1068	0
144	1
2088	0
144	1
2088	0
152	1
1060	0
140	1
1072	0
140	1
2096	0
140	1
2108	0
136	1
2088	0
148	1
1060	0
148	1
2096	0
140	1
2096	0
140	1
2092	0
148	1
2092	0
144	1
2096	0
148	1
2092	0
148	1
2092	0
144	1
1072	0
136	1
8120	0
144	1
1064	0
140	1
1076	0
136	1
2088	0
148	1
1068	0
136	1
1060	0
148	1
2088	0
144	1
1064	0
140	1
1072	0
148	1
1064	0
148	1
1064	0
140	1
1068	0
128	1
1068	0
140	1
1064	0
148	1
1064	0
144	1
1072	0
136	1
1068	0
136	1
1084	0
132	1
2100	0
128	1
1068	0
140	1
1068	0
136	1
2108	0
132	1

In Excel oder LibreOffice Calc kann man dann die Häufigkeit des Vorkommens ermitteln und daraus die Entscheidungsschwellen für die Erkennung ableiten.
Die HIGH Pegel zwischen den Datenbits sind zwischen 136 und 148us
der Synchronisierungsimpuls ist 8120us
die “0” Datenbits entsprechen 1064us
die “1” Bits entsprechen 2090us (alles ca. Werte)

erni-berni: Wenn man Glück hat und einen gültigen Datenstrom einfangen kann, sieht das ganz gut aus. Allerdings kommt wie bereits schon gesagt auch viel Müll an.

Ich glaube, ich möchte zur Vorab-Analyse von Wettersensoren lieber etwas, das mir die gültigen Datenströme automatisch einfängt und dabei nur möglichst wenig Datenmüll ausgibt.

Im besten Fall sollen nur die Wettersensoren selbst, eventuell Fragmente von den Wettersensoren aus der Nachbarschaft, die nur bruchstückhaft empfangen werden weil sie eigentlich außer Reichweite sind, und nur ganz wenig Datenmüll empfangen werden.

Und es soll rein mit Arduino funktionieren, ohne Umweg über Soundkarte oder externe Programme.

Mal schauen, was ich mir dazu selbst programmieren kann.

jurs: Mal schauen, was ich mir dazu selbst programmieren kann.

Super, ich bin sehr gespannt!

erni-berni: Die HIGH Pegel zwischen den Datenbits sind zwischen 136 und 148us der Synchronisierungsimpuls ist 8120us die "0" Datenbits entsprechen 1064us die "1" Bits entsprechen 2090us (alles ca. Werte)

So, ich habe nun nochmal etwas an den Datentelegrammen verschiedener 433 MHz Sensoren geforscht und mein Vorauswertungsprogramm für Datenpakete zeigt erste Zuckungen.

Meine Sensoren liefern allesamt längere Impulse als Dein Tchibo-Sensor, die Werte liegen mehr bei: HIGH Pegel zwischen den Bits: 475 us Startbit/Sync bei ca. 9000 us die "0" Datenbits entsprechen 2000us die "1" Bits entsprechen 4000us

Die High-Pegel von "Datenmüll" scheinen sehr oft bei weniger als 50 us zu liegen.

Ich glaube, da werde ich mir mal ein paar plausible Grenzwerte setzen, z.B.: HIGH Pegel zwischen den Bits: mindestens 50 us oder länger Startbit mindestens 5000 us oder länger "0" Datenbits mindestens 500 us oder länger "1" Bits länger als "0" Bits Anzahl der Datenbits: 20 oder mehr Und dann versuchen, was dann noch übrig bleibt an Bits einigermaßen vernünftig aus dem Äther zu fischen und als "Vorauswertung" auszugeben.

Merkwürdigerweise scheine ich verschiedene Sensoren zu haben, die ziemlich ähnliche aber trotzdem verschiedene Protokolle aussenden (identische Bit-Längen und 36-Bit Datenpakete), und trotzdem weiß die zum Sensor gehörende Basisstation, welche 36 Bits zu ihr gehören und zeigt korrekt an. Das müssen die Basisstationen dann wohl anhand von "Stationsnummern" und "Prüfsummen" unterscheiden können, welche Daten für sie bestimmt sind - und welche nicht.

Nachtrag: Ich werde es auch gleich noch kompatibel zur Erkennung von Funktelegrammen machen, die von Fernbedienungen für Funksteckdosen ausgesendet werden. Die Bitfolgen für die Steuerung von Funksteckdosen sind meisten wesentlich kürzer als die von Wettersensoren. Hier getestet mehr bei 20 Bit (Funksteckdose) statt 36 Bit (Funk-Thermometer). Außerdem ist das Startbit für die Funksteckdosen unheimlich lang: 80000 us. Das ist länger als es in einen Integer hineinpasst, da werde ich mir noch etwas einfallen lassen. Und den Sketch dann mal posten.

So ein Mist, jetzt wollte ich meinen Funkanalyes-Sketch für 433MHz-Funkgerätschaften wie handelsübliche Funk-Thermometer und Funk-Steckdosen posten, schreibe noch sehr ausführlichen Text dazu, Anwendung, Funktionsweise, Hintergründe, und dann meldet das Forum beim Posten des vollständig ausgearbeiteten Beitrags einen Fehler: Kompletter Beitrag weg!

Jetzt poste ich einfach nur mal den Code des Sketches.

/*
  Sketch zur Vorab-Analyse unbekannter 433-MHZ-Wettersensoren
  und Fernbedienungen von 433MHz-Funksteckdosen
  Inspiriert durch Beiträge im Arduino-Forum:
  http://arduino.cc/forum/index.php/topic,119739.0.html
  http://arduino.cc/forum/index.php/topic,136836.0.html
  
  Hardware: 
  1. Arduino-Board mit 433 MHz Regenerativempfänger für ASK/OOK,
  angeschlossen an einem interruptfähigen Pin.
  2. Funksensor entweder eines 433 MHz Funkthermometers 
  oder Funk-Wetterstation oder Steckdosen-Funkfernbedienung
  
  Analysiert werden können Sensoren mit folgendem Funkprotokoll:
  - extra langes Startbit (extra langer LOW Pulse am Receiver)
  - langes 1-Datenbit  (langer LOW Pulse am Receiver)
  - kurzes 0-Datenbit  (kurzer LOW Pulse am Receiver)
  - sehr kurze Trenn-Impulse zwischen den Datenbits (sehr kurze HIGH-Impulse am Receiver)
  - 20 bis 50 Datenbits pro Datenpaket
  Diese Art Funkprotokoll trifft auf die meisten billigen 433 MHZ
  Funkthermometer, Funk-Wetterstationen und Funk-Steckdosen zu.
  
  Ausgabe ueber den seriellen Monitor 
  Je erkanntem Datenpaket am Receiver wird ausgegeben:
  - Länge des Startbits (Mikrosekunden LOW) und des nachfolgenden HIGH-Impulses
  - Anzahl der erkannten Datenbits im Datenpaket
  - Länge aller erkannten Datenbits (Mikrosekunden LOW)
  - Länge der zwischen den Datenbits erkannten Pausen (Mikrosekunden HIGH)
  - die als 0/1-Bitstrom decodierten Datenbits des Datenpakets
  
  Nur Vorab-Analyse des Timings im Funkprotokoll!
  In einem weiteren Schritt muss dann die Bedeutung der Bits
  und die Umsetzung in Messwerte erst noch detalliert decodiert werden,
  dieser Sketch erkennt nur das Timing und die Groesse der Datenpakete!
*/

// connect data pin of rx433 module to a pin that can handle hardware interrupts
// with an Arduino UNO this is digital I/O pin 2 or 3 only
#define RX433DATAPIN 2

// hardware interrupt connected to the pin
// with Arduino UNO interrupt-0 belongs to pin-2, interrupt-1 to pin-3
#define RX433INTERRUPT 0

// Set speed of serial in Arduino IDE to the following value
#define SERIALSPEED 115200

// Now make some suggestions about pulse lengths that may be detected
// minimum duration (microseconds) of the start pulse
#define MINSTARTPULSE 4500

// minimum duration (microseconds) of a short bit pulse
#define MINBITPULSE 450

// minimum duration (microseconds) of a HIGH pulse between valid bits
#define MINHITIME 50

// variance between pulses that should have the same duration
#define PULSEVARIANCE 250

// minimum count of data bit pulses following the start pulse
#define MINPULSECOUNT 20

// maximum count of data bit pulses following the start pulse
#define MAXPULSECOUNT 50

// buffer sizes for buffering pulses in the interrupt handler
#define PBSIZE 216

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println("Start!");
  pinMode(RX433DATAPIN, INPUT);
  attachInterrupt(RX433INTERRUPT, rx433Handler, CHANGE);
}

volatile unsigned int pulsbuf[PBSIZE]; // ring buffer storing LOW pulse lengths
volatile unsigned int hibuf[PBSIZE]; // ring buffer storing HIGH pulse lengths
unsigned int validpulsbuf[MAXPULSECOUNT]; // linear buffer storing valid LOW pulses
unsigned int validhibuf[MAXPULSECOUNT];  // linear buffer storing valid HIGH pulses

volatile byte pbread,pbwrite;  // read and write index into ring buffer

void rx433Handler()
{
  static long rx433LineUp, rx433LineDown;
  long LowVal, HighVal;
  int rx433State = digitalRead(RX433DATAPIN); // current pin state
  if (rx433State) // pin is now HIGH
  {
    rx433LineUp=micros(); // line went HIGH after being LOW at this time
    LowVal=rx433LineUp - rx433LineDown; // calculate the LOW pulse time
    if (LowVal>MINBITPULSE)
    { // store pulse in ring buffer only if duration is longer than MINBITPULSE
      // To be able to store startpulses of more than Maxint duration, we dont't store the actual time,
     // but we store  MINSTARTPULSE+LowVal/10, be sure to calculate back showing the startpulse length!
      if (LowVal>MINSTARTPULSE) LowVal=MINSTARTPULSE+LowVal/10; // we will store this as unsigned int, so do range checking

      pulsbuf[pbwrite]=LowVal; // store the LOW pulse length
      pbwrite++;  // advance write pointer in ringbuffer
      if (pbwrite>=PBSIZE) pbwrite=0; // ring buffer is at its end
    }  
  }
  else 
  {
    rx433LineDown=micros(); // line went LOW after being HIGH
    HighVal=rx433LineDown - rx433LineUp; // calculate the HIGH pulse time
    if (HighVal>31999) HighVal=31999; // we will store this as unsigned int
    hibuf[pbwrite]=HighVal; // store the HIGH pulse length
  }
}


boolean counting;
byte i,counter;
int startBitDurationL,startBitDurationH,shortBitDuration,longBitDuration;

void showBuffer()
// this function will show the results on the serial monitor
// output will be shown if more bits than MINPULSECOUNT have been collected
{
  long sum;
  int avg;
  sum=0;
  if (counter>=MINPULSECOUNT)
  { // only show buffer contents if it has enough bits in it
    Serial.println();
    Serial.print("Start Bit L: "); Serial.print((startBitDurationL-MINSTARTPULSE)*10L);
    Serial.print("   H: ");Serial.println(startBitDurationH);
    Serial.print("Data Bits: ");Serial.println(counter);
    Serial.print("L: ");
    for (i=0;i<counter;i++)
    {
      Serial.print(validpulsbuf[i]);Serial.print(" ");
      sum+=validpulsbuf[i];
    }
    Serial.println();

    Serial.print("H: ");
    for (i=0;i<counter;i++)
    {
      Serial.print(validhibuf[i]);Serial.print(" ");
    }
    Serial.println();

    avg=sum/counter; // calculate the average pulse length
    // then assume that 0-bits are shorter than avg, 1-bits are longer than avg
    for (i=0;i<counter;i++)
    {
      if (validpulsbuf[i]<avg) Serial.print('0'); else Serial.print('1');
    }
    Serial.println();
  
  }
  counting=false;
  counter=0;
}
 
void loop() 
{
  long lowtime, hitime;
  if (pbread!=pbwrite) // check for data in ring buffer
  {
    lowtime=pulsbuf[pbread]; // read data from ring buffer
    hitime=hibuf[pbread];
    cli(); // Interrupts off while changing the read pointer for the ringbuffer
    pbread++;
    if (pbread>=PBSIZE) pbread=0;
    sei(); // Interrupts on again
    if (lowtime>MINSTARTPULSE) // we found a valid startbit!
    {
      if (counting) showBuffer(); // new buffer starts while old is still counting, show it first      
      startBitDurationL=lowtime;
      startBitDurationH=hitime;
      counting=true;     // then start collecting bits
      counter=0;         // no data bits yet
    }
    else if (counting && (counter==0)) // we now see the first data bit
    { // this may be a 0-bit or a 1-bit, so make some assumption about max/min lengths of data bits that will follow
      shortBitDuration=lowtime/2;
      if (shortBitDuration<MINBITPULSE+PULSEVARIANCE)
        shortBitDuration=MINBITPULSE;
      else  
        shortBitDuration-=PULSEVARIANCE;
      longBitDuration=lowtime*2+PULSEVARIANCE;
      validpulsbuf[counter]=lowtime;
      validhibuf[counter]=hitime;
      counter++;
    }
    else if (counting&&(lowtime>shortBitDuration)&&(lowtime<longBitDuration))
    {
      validpulsbuf[counter]=lowtime;
      validhibuf[counter]=hitime;
      counter++;
      if ((counter==MAXPULSECOUNT) || (hitime<MINHITIME))
      {
        showBuffer();
      }  
    }
    else // Low Pulse is too short
    {
      if (counting) showBuffer();
      counting=false;
      counter=0;
    }  
  }
}

Ich habe jetzt keine Lust mehr, da nochmal zwanzig Minuten lang was zu schreiben und dann frisst das Forum den Text auf.
:frowning:

Wer Fragen hat, kann ja fragen.
Feedback erwünscht!