-->
Page 1 of 1

Decoding of 433 MHz Weather Station Sensor

PostPosted: Mon Apr 06, 2020 3:01 am
by Gandalf
Hello all toghether,

I have an ESP8266 NodeMCU and connected a 433 MHz receiver to it. I can receive correct signals from a remote control, so the hardware is working correctly.

I have got an inFactory NC-3982 temperature/humidity sensor. In the RTL_433 library, that sensor is listed and so the decoding is documented: infactory.c source file.

But I'm not able to decode that signal with other libraries like rc-switch or ESPiLight, which are running natively on an ESP-8266.
These libraries detect signals from the sensor, but the received data variies in the length and they look not plausible. So a decoding is not possible.

I found the following Arduino sketch here:

Code: Select all/*
  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 5

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

// 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 8500

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

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

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

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

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

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

void setup()
{
  Serial.begin(SERIALSPEED);
  Serial.println();
  Serial.println("Start!");
  pinMode(RX433DATAPIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(RX433DATAPIN), 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

ICACHE_RAM_ATTR void rx433Handler()
{
  //Serial.print("Interrupt");
  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;
    }
  }
}


The received data are the following as an example. The data differs:

Code: Select all09:56:33.371 -> Start Bit L: 15830   H: 28
09:56:33.371 -> Data Bits: 17
09:56:33.405 -> L: 1876 1877 4079 1977 1877 4073 4177 1880 2746 2760 1980 3986 1882 1882 4046 3114 2987
09:56:33.405 -> H: 579 565 563 560 564 565 561 563 562 562 561 554 560 558 561 562 51
09:56:33.405 -> 00100110000100111
09:56:33.507 ->
09:56:33.507 -> Start Bit L: 11220   H: 25
09:56:33.507 -> Data Bits: 10
09:56:33.507 -> L: 4696 1877 1878 3110 1979 1879 2833 4175 1880 3224
09:56:33.541 -> H: 569 576 562 561 560 561 561 559 563 28
09:56:33.541 -> 1001001101


And I also tried the other mentioned libraries rc-switch and ESPiLight and they also received varying data from that sensor.

Is there anybody how can help me to decode that sensor signal?

Best regards

Re: Decoding of 433 MHz Weather Station Sensor

PostPosted: Mon Apr 06, 2020 3:38 pm
by AcmeUK
Have you tried using rtl_433_win?
https://github.com/winterrace/rtl_433_win
The first step in decoding new devices is to record the signals using -S all