Home Automation – Receiver

 Arduino, DIY, Electronics, Home Automation  Comments Off on Home Automation – Receiver
Aug 112015
 

I have made a couple of attempts over the past years to make a Home Automation Receiver with an Arduino Uno and a simple 433MHz receiver.
But so far I have failed, believing the Uno maybe wasn't fast enough for the task at hand.
By chance a colleague of mine stumbled upon my blog, and wondered if I did not have any such receiver at hand, since I had made transmitters way back in time.
I told him about my endeavors and my disbelief about the performance. Luckily he did not listen too much, and did some internet searching.
Of course there are sketches out there for the receiver task. After looking at some of them I decided to try to do one myself.
One major difference in my new sketch, compared to my older attempts, is the use of pulseIn(). Before I tried to sample with digitalRead()  but could never get a consistent result.
With pulseIn() we detect only the low part of the pulses, and by comparing the length of the low part, conclude what type of bit it was.

This is what the HW setup looks like.
DSC_0952

Here is the sketch.

/*
   Joakim Wesslen
   2015-08-10

   We detect data pulses by catching the low part of every pulse.   

*/

/*
More info at:  
http://tech.jolowe.se/home-automation-rf-protocol-update/
http://tech.jolowe.se/home-automation-rf-protocols/


Physical data structure (in air):
Bit
0        10        20        30        40        50           60
1234567890123456789012345678901234567890123456789012 34 56 7890 1234
--------------------------------------------------------------------
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT GG OO DDDD NNNN

Bits #01-52 -> TxCode (T)
Bits #53-54 -> Group (G)
Bits #55-56 -> On/Off (O)
Bits #57-60 -> ? Dimming/Channel ? (D)
Bits #61-64 -> Device Nbr (N)


Logical data structure:
0        10        20           30  
12345678901234567890123456 7 8 90 12
------------------------------------
TTTTTTTTTTTTTTTTTTTTTTTTTT G O DD NN

Bits #01-26 -> TxCode (T)
Bits #27 -> Group (G)
Bits #28 -> On/Off (O)
Bits #29-30 -> ? Dimming/Channel ? (D)
Bits #31-32 -> Device Nbr (N)

*/


int rxPin = 12;

boolean debugOn = false;  // enable debug prints

int tPause = 0; // debugging
int tSync = 0; // debugging

unsigned long loopCounter = 0;  // stats
unsigned long dataCounter = 0;  // stats

// Setting limit boundaries
int pauseMinTime = 7000;
int pauseMaxTime = 14000;

int syncMinTime = 2100;
int syncMaxTime =  3200;
 
int oneMinTime = 70;
int oneMaxTime = 300;

int zeroMinTime = 1000;
int zeroMaxTime = 1900;

signed long timeout1 = 1000000;
signed long timeout2 = 100000;


#define MAX_STR 150

char bin[MAX_STR + 1];

// get a 'binary' 32 bit string from value
char *dec2binStr(unsigned long ul)
{
 int len = sizeof(ul) * 8;
  int c, d;
  int count = 0;

  memset(bin, len, '0');

  for (c = len-1 ; c >= 0 ; c-- )
  {
    d = ul >> c;

    if ( d & 1 )
       bin[count] = '1';
    else
       bin[count] = '0';
    
    count++;
  }
  bin[len] = '\n';
  return bin;
}

// log function
void ilog(const char *fmt, ...)
{
  char tmpStr[MAX_STR + 1];
  va_list ap;

  va_start(ap, fmt);
  vsnprintf(tmpStr, MAX_STR + 1, fmt, ap);
  va_end(ap);
  Serial.println(tmpStr);
}

// debug log function
void dlog(const char *fmt, ...)
{
  if (debugOn) 
  {
    char tmpStr[MAX_STR + 1];
    va_list ap;

    va_start(ap, fmt);
    vsnprintf(tmpStr, MAX_STR + 1, fmt, ap);
    va_end(ap);
    Serial.println(tmpStr);
  }
}

char binPhy[MAX_STR + 1];

// get a 'binary' 64 bit string from value
char *dec2binPhyStr(unsigned long ul)
{
 int len = sizeof(ul) * 8;
  int c, d;
  int count = 0;

  memset(binPhy, MAX_STR, '0');

  for (c = len-1 ; c >= 0 ; c-- )
  {
    d = ul >> c;

    if ( d & 1 )
    {
       binPhy[count] = '1';
       binPhy[count+1] = '0';
    }
    else
    {
       binPhy[count] = '0';
       binPhy[count+1] = '1';
    }
    
    count += 2;
  }
  binPhy[len*2] = '\n';
  return binPhy;
}

// debug statistics printout
void printStats(unsigned long loopCnt, unsigned long dataCnt)
{
  ilog("Loops: %d, Packets: %d", loopCnt, dataCnt);
}

// print decoded receiver data
void printPacketData(unsigned long data)
{
  ilog("Received: %s", dec2binStr(data));
//  ilog("ReceivedPhy: %s", dec2binPhyStr(data));
}

// receiver for home automation data
void dataReceiver(void)
{
  dlog("--- Wait for Pause and Sync ---");

start_over:  
  int i = 0;
  signed long t = 0;
  
  byte prevBit = 0;
  byte currBit = 0;
  
  // Packet data, logical structure
  unsigned long dataPacket = 0;

  loopCounter++;
  
  // Wait for Pause bit (10500 us).
  while ((t < pauseMinTime) || (t > pauseMaxTime))
  { 
    t = pulseIn(rxPin, LOW, timeout1);
  }
  tPause = t; // Save timing for debugging purposes
  if (t == 0)
  {
    dlog("!!! - Pause Timeout - Start over.");
    goto start_over;
  }

  // Wait for Sync bit (2750 us).
  while ((t < syncMinTime) || (t > syncMaxTime))
  { 
    t = pulseIn(rxPin, LOW, timeout1);
  }
  tSync = t; // Save timing for debugging purposes
  if (t == 0)
  {
    dlog("!!! - Sync Timeout - Start over.");
    goto start_over;
  }

  // data collection loop
  while (i < 64)
  {
    t = pulseIn(rxPin, LOW, timeout2);  // shorter timeout?
    if (t == 0)
    {
      dlog("!!! - Data Timeout - Start over.");
      goto start_over;
    }
    else if (t > zeroMinTime && t < zeroMaxTime)
    {
      currBit = 0;
    }
    else if (t > oneMinTime && t < oneMaxTime)
    { 
      currBit = 1;
    }
    else
    { 
      dlog("Incorrect data - Start over. t=%d", t);
      goto start_over;
    }

    if (i % 2 == 1)
    {
      if ((prevBit ^ currBit) == 0)
      { 
        // must be either 01 or 10, not allowed to be 00 or 11
        dlog("Bad data - Start over");
        goto start_over;
      }
  
      // Store packet bits
      dataPacket <<= 1;
      dataPacket |= prevBit;
     }
     prevBit = currBit;
     ++i;
   }
   if (i > 0)
   { 
     dataCounter++;
     printPacketData(dataPacket);
   }
}


void setup()
{ 
  pinMode(rxPin, INPUT);
  
  Serial.begin(9600);
  ilog("Home Automation Receiver");
}


void loop()
{
  dataReceiver();
}

Next, I shall try and make this into a library.