Saturday, October 4, 2014

Studying the TPMS signals from Subaru a.k.a. Schrader signals

1) Observing the car at standstill produced no signals. Even after driving.

Data collection: So far windows and HDSDR have been used. SDR# is not available to me, Neither a portable coputer with gnuradio. Recordings produced files that ended like this: 433789kHz_RF.wav Stereosignals in Audacity with something that looked like quadrature detection. Is this the I/Q?

2) While driving, an some signals were registered, approx one every 14 seconds.


The first part of the signal is constant, the second part varies.  48 bits. 8 first bits a short pulse. The second part is closer to the resonance frequency. Driving on, I never manage to observe this signal again. Maybe a local, exterior signal?


3) After some fiddeling with parameters, some other signal are observed.

I first processed these data with a low pass filter, then a normalization. Not wise, a repeating signal is also observed without the initial low pass filter:



Eight groups of packets, separated by 100 ms.



The packets are not yet analyzed, could this signal shape indicate FSK? Seems to be three different pulse lengths in the packet.  Like Jared Boon is taking about here.

Screendump from HDSDR:



Monday, September 29, 2014

Decoding Biltema Weatherstation 84086 / sensor 84056


This weather station is sold with one remote sensor and a base station capable of monitoring airpressure. It also have a radio controlled clock.

The remote sensor is capable of measuring temperature and pressure and broadcast this information on the 433 MHz band.

Using a 433 MHz receiver together with a logic analyzer several things could be learned:

The sensor transmit 20 bits of information starting with a 1.45 ms pulse followed by 1.50 ms silence. Pulses 2.16 ms long followed by 0.77 ms silence is '1', and 0.70 ms pulses followed by 2.23 ms silence is representing '0'.


Channel 2, -16.6C, 20% humidity

Several different measurements obtained with varying temperatures and constant humidity (36% (0b100100)) showed that the sensor transmitted the humidity in the seven last bits of the transmission.

The last seven bits is arranged in the following fashion: bit 1, 0 , 6, 5, 4, 3 and 2.

Yeah, and after some googling I found that the decoded signals were presented at telldus.com.

In the following table this decoding is used with the exception of me rotating the bitorder.





Tuesday, April 8, 2014

Turning NEXA recievers on and off from the light switch

So, the switch in question is divided into three parts, for controlling three different lights. One of these is an outlet located close to the ceiling, just above a cupboard.

The most elegant solution would be to hook this outlet up to the device controlling the Nexa switches. Power comes on, send signal for turning on the Nexa switches. Power dissapears, send signal for turning off the Nexa switches.

This requires us to detect the power off from the outlet and send the OFF signal before the power is totally gone.



Using a 9V (more like 12V) 200 mA AC adaptor and hooking the outputs of this circuit to a atiny13A MCU and a standard Itead 433 MHz radio, using the attiny13a to detect when the voltage dropped from 'V detect' the following were obtained:

R1 360 Ohm
R2 180 Ohm
D1 1N4001
C1  1000uF, 50V
Radio operates 650 ms after 'V detect' goes low.

Since the Nexa transmission requires ca. 400 ms, no modifications to this setup were necessary. The NEXA protocol is described here.


The attiny13A is programmed to send the ON signal when the power comes on. It then enters a loop waiting for the voltage indicator to drop and then sends the OFF signal.


Voltage drops at '1', radio stops sending at '2'.

 /*
  * Lysbryter.c
  *
  * Created: 4/6/2014 12:11:38 PM
  * Author: hwa
  */  
 #define F_CPU 8000000
 #include <avr/io.h>
 #include <util/delay.h>
 #define RPORT PINB0
 void send_signal(uint32_t ID, uint8_t GRP, uint8_t ON, uint8_t UNIT);
 void pulse();
 void pulse()
 {
      PORTB |= (1<<RPORT);
      _delay_us(230);
      PORTB &= ~(1<<RPORT);
 }
 // delays determining '0' or '1'
 #define SHORTDELAY 400
 #define LONGDELAY 1420
 void send_signal(uint32_t ID, uint8_t GRP, uint8_t ON, uint8_t UNIT)
 {
      uint16_t t1,t2;
      t1 = (ID>>10);
      t2 = (ID<<6);
      if (GRP==1)
      {
           t2 |=1<<5; //Group command
      }
      if (ON==1)
      {
           t2 |= 1<<4; //ON
      }
      // ORin UNIT
      t2 = t2 | (UNIT & 0x0F);
      pulse();
      _delay_us(1000);
      _delay_us(1000);
      _delay_us(825);
      for (int i =15;i>=0;i--)
      {
           if (((t1) & (1 << i)) == 0)//Console::WriteLine("0");
           {
                pulse();
                _delay_us(SHORTDELAY);
                pulse();
                _delay_us(LONGDELAY);
           }                
           else//Console::WriteLine("1");
           {
                pulse();
                _delay_us(LONGDELAY);
                pulse();
                _delay_us(SHORTDELAY);
           }
      }
      for (int i =15;i>=0;i--)
      {
           if (((t2) & (1 << i)) == 0)//Console::WriteLine("0");
           {
                pulse();
                _delay_us(SHORTDELAY);
                pulse();
                _delay_us(LONGDELAY);
           }                
           else//Console::WriteLine("1");
           {
                pulse();
                _delay_us(LONGDELAY);
                pulse();
                _delay_us(SHORTDELAY);
           }
      }
      pulse();
 }
 int main(void)
 {
      int nopower = 0;
      //DDRB &= ~(1<<PINB4);
      DDRB=0;
      DDRB |= (1<<PINB0); // output
      PORTB &= ~(1<<PINB0); //off
      //PORTB &= ~(1<<PINB4); //pullup
      _delay_ms(100);
      // send turn on signal to the group
      for (int i =0;i<7;i++)
      {
           send_signal(0x280526, 1,1,0);
           _delay_ms(11);
      }
   while(1)
   {
            if(bit_is_clear(PINB, PINB4))  
            {
                nopower = 1;  
           }          
           if (nopower==1)
           {
                for (int i =0;i<7;i++)
                {
                     send_signal(0x280526, 1, 0, 0); //off
                     _delay_ms(11);
                }
           }
      }
 }

Looking at the source code it is apparent that one could have used a function 'calculate_signalstring' which returned the bits to send thus eliminating the need for recomputation each time 'send_signal' was executed. '0x280526' is the ID code for my Nexa remote.


Signal from the ATtiny13A
It did appear that the reciever were forgiving with the exact pulsewidth and pulse delays in the sequence. Two initial adjustments were all it took to make the reciever accept the signal.
Signal from the NEXA remote
Looking at the last six bits of these patterns it is apparent that the attiny13A is sending the group/off signal while the remote sends the unit 1 on signal.