Friday, August 29, 2014

Raspberry pi as an nrf24l01 base station with python for smart home or internet of anything projects

ADVERTISEMENT


Internet connectivity in an integral part of  various micro-controller projects, specifically those using the atmega328p with arduino ide/avr-gcc. NRF24l01 modules provide an inexpensive and reliable wireless link. In many projects, an additional avr/arduino is hooked up to a computer with internet connection for linking the projects to the internet. Here i will summarize my experience with raspberry pi as an internet gateway for various projects which uses nrf24l01 to wirelessly transfer data.

A simple shield for nrf24l01 and ir receiver


Connector for GPIO pins on PI


Modmypi case with nrf shield and an ir receiver for raspbmc

Nrfmodule is directly attached to the raspberry pi GPIO (see figure). The connections are the same as in my previous post (Testing an nrf24l01 module with raspberry pi). For a cleaner solution, i am using  a small piece of general purpose pcb and a pair of connectors to mount the nrf module directly over the Pi. The whole setting is running in a raspberry pi with raspbmc, a port of xbmc (now osmc). Raspberry pi is kept on all the time ( as the power consumption is very low) and can collect the sensor data from various devices and hence can be updated online.

Arduino part of the projects are wired in the same manner as in my previous post on nrf24l01 with arduino. (see here for quickly hooking up the module and testing the pin connections)

The key idea of this projects were to
  1.  Keep everything compact and keep the raspberry pi always on as an internet gateway for all sort of home     automation/sensor network projects
  2. Using python (instead of c program) on the raspberry side for flexibility in scripting / playing the strings from sensors and pushing it to various cloud services/ local storage (mysql)
  3. Send sensor information as small strings for easier handling at the python side.
  4. Keeping the arduino ends sleeps most of the time for battery operated projects
  5. keep the installation process faster and reproducible

Python friendly installation of nrf24l01 

This was one of the difficult part. I used raspbmc and recent versions has spi support in the kernel. Furthermore, you can use the pi to watch internet streams and media files, making the best use of the setup.

Execute the command in sequence as given below to get the module up and running.

1. Getting the tools

 # get the necessary packages  
 sudo apt-get install python-dev  
 #needed to install the python modules  
 sudo apt-get install build-essential 
 #install git for easy code access
 sudo apt-get install git-core 

2. Installing the modules


git clone https://github.com/riyas-org/nrf24pihub
cd nrf24pihub
cd python-spi
sudo python setup.py install
cd ../RPi.GPIO-0.5.11
sudo python setup.py install
cd ..


Example application : wireless temperature logger DS18S20

Here is a simple example where a ds1820 based temperature sensor will record and wirelessly send the temperature from out side the building to the raspberry pi.

The temperature sensor is attached to the digital pin 7 on the arduino. NRF module is connected as described above and on the raspberry pi a python script will be running , which displays the temperature. The example program is located in nrf24pihub folder (raspberryfriend.py)

DS18S20 connections
Arduino sketch

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
// For using the temperature sensor DS18S20
#include <OneWire.h> 
int DS18S20_Pin = 8; //DS18S20 Signal pin on digital 2
OneWire ds(DS18S20_Pin);  // on digital pin 2

//for nrf24 debug
int serial_putc( char c, FILE * ) 
{
  Serial.write( c );
  return c;
} 

//for nrf24 debug
void printf_begin(void)
{
  fdevopen( &serial_putc, 0 );
}

//nRF24 set the pin 9 to CE and 10 to CSN/SS
// Cables are:
//     SS       -> 10
//     MOSI     -> 11
//     MISO     -> 12
//     SCK      -> 13

RF24 radio(9,10);

//we only need a write pipe, but am planning to use it later
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL,0xF0F0F0F0D2LL };

// here we can send up to 30 chars
char SendPayload[31] = "blog.riyas.org";

void setup(void) {
  Serial.begin(57600); //Debug 
  printf_begin();
  //nRF24 configurations
  radio.begin();
  radio.setChannel(0x4c);
  radio.setAutoAck(1);
  radio.setRetries(15,15);
  radio.setDataRate(RF24_250KBPS);
  radio.setPayloadSize(32);
  radio.openReadingPipe(1,pipes[0]);
  radio.openWritingPipe(pipes[1]);
  radio.startListening();
  radio.printDetails(); //for Debugging
}

void loop() {
  
  //Get temperature from sensor
    float temperature = getTemp();
  // Assign temperature to payload, here am sending it as string
  dtostrf(temperature,2,2,SendPayload);
  
  //add a tag
  strcat(SendPayload, "X");   // add first string

  //send a heartbeat
  radio.stopListening();
  bool ok = radio.write(&SendPayload,strlen(SendPayload));
  radio.startListening(); 
  //Serial.println(SendPayload);  

  // slow down a bit
  delay(1000);  
}


// Getting temperature from DS18S20

float getTemp(){
  //returns the temperature from one DS18S20 in DEG Celsius

  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE); // Read Scratchpad

  
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }
  
  ds.reset_search();
  
  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;
  
  return TemperatureSum;
  
}



Raspberry pi code (it is already downloaded from github when you installed the modules). You can see it here

So on the raspberry pi execute it with sudo ( soo as to access the spi device)

sudo python raspberryfriend.py

You can place multiple sensors at different places and use different string suffix/ prefix to identify them and then use python to process them further

Here is a snapshot after keeping the sensor in a refrigerator (it is still cooling down from room temperature)

Sensor reading from refrigerator (while cooling down)


An alternate solution for remote temperature monitoring based on a pair of arduinos and 433mhz rf link can be seen in previous article here

Sending multiple sensor values  to the Raspberry pi nrf24l01 hub and storing it in a csv file

It is easy to send multiple sensor values by packing it in the 32 bytes space (for simple values). Here i modified the script a little bit by adding some tags (for eg T or P) to indicate the payload.

Eg NODE1T23.45TP45PH34H where value between P is pressure, T is temperature and so on

You can download the sketch from github

At the raspberry pi end, a modified python script is used to write the values in to a csv file with date and time followed by sensor values.

In case of multiple nodes, it is wise to add a node specific Payload and process accordingly.

For a better and easy maintenance, it would be easier to use a mysql database. Also take care of the SD card , if you plan to keep it running for longer duration's (as the attached script writes each values as soon as received to SD)

You may see the simple receiver code for the Raspberry pi at here

A compatible arduino sketch for dht sensor can be downloaded here

Newer Models of the Pi (B+) with 40 pins


With new models of raspberry pi with 40 pins, it appears that the first 26 pins remains similar and hence if you count the pins correctly, there wont be any issue in getting this codes up and running. see more on pin layout and comparisons from a nice article in raspi.tv and an other excellent article in elinux

Pin layout on the pi (identical zones are shown with a dotted  red line)


39 comments:

  1. FAQ:


    I want to transmit data from arduino to Rpi using nrf24l01 modules . I connected it as per the instructions given by you . I just want to transmit only numbers not the temperature . How should i change the code ? please help ...

    ---


    In the arduino sketch see the following lines in side the void loop()


    .......

    ........


    //Get temperature from sensor
    float temperature = getTemp();
    // Assign temperature to payload, here am sending it as string
    dtostrf(temperature,2,2,SendPayload);

    .........
    .........

    So instead of float temperature = getTemp() you can assign any float and it gets transmitted to the pi

    for eg

    .....

    float temperature = 12.2;
    // Assign temperature to payload, here am sending it as string
    dtostrf(temperature,2,2,SendPayload);
    .......

    ReplyDelete
  2. Good job.
    It works perfectly .
    Can you tell me how I can modify the code of the Raspberry Pi to send data to arduino.
    Tanks !!!

    ReplyDelete
  3. How would I add the 2nd - 8th temperature probes to the arduino code? I have everything working great with one probe on the arduino.

    Rod

    ReplyDelete
  4. I am getting this error from the python code when ran on a RPI B+:

    /home/pi/nrf24pihub/nrf24.py:374: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
    GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    Traceback (most recent call last):
    File "raspberryfriend.py", line 13, in
    radio.begin(0, 0,25,18) #set gpio 25 as CE pin
    File "/home/pi/nrf24pihub/nrf24.py", line 381, in begin
    self.write_register(NRF24.SETUP_RETR, (int('0100', 2) << NRF24.ARD) | (int('1111', 2) << NRF24.ARC))
    File "/home/pi/nrf24pihub/nrf24.py", line 239, in write_register
    return self.spidev.xfer2(buf)[0]
    IOError: [Errno 22] Invalid argument

    Any ideas how to fix this???

    ReplyDelete
    Replies
    1. I am also getting this same error, any idea on how to fix it?

      Delete
    2. I am also getting the same error, any idea on how to fix it?

      Delete
    3. I have been able to get past this error. To be honest, I have done so much to get things work I can't remember which did what! But two things I recall:

      1. The SPI has issues in the latest upgrade to Linux/Raspbian. You can find a fix here: http://raspberrypi.stackexchange.com/questions/27073/firmware-3-18-x-breaks-i2c-spi-audio-lirc-1-wire-e-g-dev-i2c-1-no-such-f

      2. Go here:http://www.raspberrypi.org/forums/viewtopic.php?f=32&t=98070&p=681410#p681410
      Find "seanspins211" (me) and follow the response to my question.

      Everything has been fine since I followed both of these steps. Hope it helps you, too!

      Delete
    4. Got the SPI part working, thank you.

      Delete
    5. I got the SPI part working but now i am not sure if the nrf module is getting configured i get this message



      [email protected] ~/nrf24pihub $ sudo python raspberryfriend.py
      /home/pi/nrf24pihub/nrf24.py:373: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
      GPIO.setup(self.ce_pin, GPIO.OUT)
      STATUS = 0x00 RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=0 TX_FULL=0
      RX_ADDR_P0-1 = 0x0000000000 0x0000000000
      RX_ADDR_P2-5 = 0x00 0x00 0x00 0x00
      TX_ADDR = 0x0000000000
      RX_PW_P0-6 = 0x00 0x00 0x00 0x00 0x00 0x00
      EN_AA = 0x00
      EN_RXADDR = 0x00
      RF_CH = 0x00
      RF_SETUP = 0x00
      CONFIG = 0x00
      DYNPD/FEATURE = 0x00 0x00
      Data Rate = 1MBPS
      Model = nRF24L01
      CRC Length = Disabled
      PA Power = PA_MIN

      After this it just keeps scrolling down in the r -pi and if i exit the program using ctrl+ C, i get this message:-


      ^CTraceback (most recent call last):
      File "raspberryfriend.py", line 31, in
      while not radio.available(pipe, True):
      File "/home/pi/nrf24pihub/nrf24.py", line 513, in available
      self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR))
      File "/home/pi/nrf24pihub/nrf24.py", line 239, in write_register
      return self.spidev.xfer2(buf)[0]
      KeyboardInterrupt
      [email protected] ~/nrf24pihub $

      Delete
    6. Is it your wiring? All zeros mean something is wrong. Make sure the pins written in radio() correspond to where you have connected the wires

      Delete
    7. This is a typical case of faulty connection or "spi not working"
      Fix spi on the raspberry pi based on the kernel used. If raspbmc, enabling bob light will activate spi

      Delete
  5. Okay, this comment section sucks for me. I have had to write this three times.. :\

    Devices all test fine on the RasPi and Arduino

    Devices:
    - DS18B20 - temp sensor
    - nRF24L01+ Modules

    I have tested scanner on both Arduino and RasPi and they work. I have tested the temp sensor on arduino using test sketch.

    I cannot seem to get anything back to the RasPi from the Arduino with the temp sensor.

    ReplyDelete
    Replies
    1. Okay, I'm finally getting someplace.. Sorta

      I found that you had this line of code wrong in the Arduino code:

      int DS18B20_Pin = 7; //DS18S20 Signal pin on digital 2 (I changed it to 7 to match the wiring diagram and it read temps now in your sketch.

      Now, I am getting a read out to the RasPi but it is totally at a random time/one time and not quite like I expected. I thought that every time the arduino read the temp it would send to the RasPi?

      One other thing that I am noticing is the DYNPD/FEATURE of the RasPI reads: 0x00 0x00 while the Arduino reads 0x00 0x04. Would this have an affect and how do I change it if so?

      Thanks in advance for all your time and help. Trying to figure out how to make this work to avoid using Arduino RFM gateway and Arduino Ethernet (MQTT) gateway to the RasPi as seen in this tutorial: http://www.instructables.com/id/Uber-Home-Automation/step3/

      Delete
    2. Scratch that last transmission. I seemed to be able to get it working now by changing a few lines of code.

      I changed the DataRate to 2MBPS and it started communicating right away.

      Delete
    3. ***I finally got this to work+++
      I changed the Data Rate to 2MBPS on the arduino and RasPi and it seemed to communicate with the RasPi a lot quicker, then

      I changed the section in the raspberryfriend.py

      time.sleep(1000/1000000.0) changed to time.sleep(1)

      and poof it works fine now!!

      Delete
  6. STATUS = 0x00 RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=0 TX_FULL=0
    RX_ADDR_P0-1 = 0x0000000000 0x0000000000
    RX_ADDR_P2-5 = 0x00 0x00 0x00 0x00
    TX_ADDR = 0x0000000000
    RX_PW_P0-6 = 0x00 0x00 0x00 0x00 0x00 0x00
    EN_AA = 0x00
    EN_RXADDR = 0x00
    RF_CH = 0x00
    RF_SETUP = 0x00
    CONFIG = 0x00
    DYNPD/FEATURE = 0x00 0x00
    Data Rate = 1MBPS
    Model = nRF24L01
    CRC Length = Disabled
    PA Power = PA_MIN


    I am now getting an error like this, the wifi scanner program works fine.

    ReplyDelete
  7. Any chance you could do an update to this with the new 3.18.5 kernel? I had it all working with the 3.12(?) kernel.

    Thanks,
    Rod

    ReplyDelete
    Replies
    1. Give a try with Adding

      “dtparam=spi=on” to your /boot/config.txt and reboot.

      https://raspberrypi.stackexchange.com/questions/27073/firmware-3-18-x-breaks-i2c-spi-audio-lirc-1-wire-e-g-dev-i2c-1-no-such-f?newreg=d5f1e383852548aa9ec8158b694371f9
      http://www.raspberrypi.org/forums/viewtopic.php?p=675658#p675658

      Delete
  8. Any chance you could update based on the 3.18.5 kernel and the new SPI device tree? I had it working previously and now nothing but hieroglyphics...

    ReplyDelete
  9. Thanks for writing this artical. I've been able to getting everything up and running and had a lot of fun doing it. Do you have any advice on how to use the data after receiving it from the nrf24l01. Is there a way to send the data from the raspberryfriend.py program to a csv file or to a program like Conky? Or othe ideas?

    ReplyDelete
  10. Thanks for writing this artical. I've been able to getting everything up and running and had a lot of fun doing it. Do you have any advice on how to use the data after receiving it from the nrf24l01. Is there a way to send the data from the raspberryfriend.py program to a csv file or to a program like Conky? Or othe ideas?

    ReplyDelete
    Replies
    1. I haven't tested yet, but see https://raw.githubusercontent.com/riyas-org/nrf24pihub/master/csvraspberryfriend.py

      It should write it to a csv. The best idea is to write in to a mysql database.

      Delete
  11. Thank you for this article!! I have everything working, but now I want to increase the information the arduino sends back to the pi base station. I've hit the payload max and need to send it in two messages, but I'm not having any success. How would you clear the buffer and (maybe) ack back to the arduino to send the send message?
    Thanks,
    Mike

    ReplyDelete
  12. [email protected] ~/nrf24pihub $ sudo python csvraspberryfriend.py
    Traceback (most recent call last):
    File "csvraspberryfriend.py", line 9, in
    from nrf24 import NRF24
    File "/home/pi/nrf24pihub/nrf24.py", line 21, in
    import RPi.GPIO as GPIO
    RuntimeError: This module can only be run on a Raspberry Pi! <---------That's what I'm doing !! (RPi2)

    ReplyDelete
    Replies
    1. The code for rpi.gpio is older (and for older pi). Update the rpi.gpio modules for python (get the latest)and it may solve the error. I dont have a recent version of the pi to test.

      Delete
    2. Updated the latest gpio library, you may try if this works

      First delete the old folder by rm -rf rf24pihub and then

      git clone https://github.com/riyas-org/nrf24pihub
      cd nrf24pihub
      cd python-spi
      sudo python setup.py install
      cd ../RPi.GPIO-0.5.11
      sudo python setup.py install
      cd ..

      Delete
  13. With the updated (latest) gpio library I get:

    [email protected] ~/nrf24pihub $ sudo python csvraspberryfriend.py
    /home/pi/nrf24pihub/nrf24.py:373: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
    GPIO.setup(self.ce_pin, GPIO.OUT)
    Traceback (most recent call last):
    File "csvraspberryfriend.py", line 17, in
    radio.begin(0, 0,25,18) #set gpio 25 as CE pin
    File "/home/pi/nrf24pihub/nrf24.py", line 381, in begin
    self.write_register(NRF24.SETUP_RETR, (int('0100', 2) << NRF24.ARD) | (int('1111', 2) << NRF24.ARC))
    File "/home/pi/nrf24pihub/nrf24.py", line 239, in write_register
    return self.spidev.xfer2(buf)[0]
    IOError: [Errno 22] Invalid argument
    [email protected] ~/nrf24pihub $

    ReplyDelete
    Replies
    1. Kernel version? There is an issue with spi in latest kernels. There is a solution at https://www.raspberrypi.org/forums/viewtopic.php?p=680726#p680726

      Delete
  14. ı am using Raspberry pi b+ and it didnt work. Help me ?????????

    ReplyDelete
  15. Check /boot/config.txt and enable SPI
    Check if CE of NRF is connected to GPIO25 (Pin 22)
    Check version of spidev with pip freeze command and if it is 2.0 upgrade with "pip install --upgrade spidev" to 3.0
    delete the version of nrf24pihub directory and get it from GIT again and just setup the GPIO .05.11
    Change both TX on Arduino and RX and RPI to say 1MBPS

    ReplyDelete
  16. Hello,
    Great project, thank you.
    I have communication between Arduino to RPi 2, but I can't determine send interval - data is received randomly - from one second up to 5 second. As I'm new in RPi and Arduino coding, is there any way to see which part is fault - Arduino or RPi.

    Thanks
    Aleksandar

    ReplyDelete
  17. Hi,
    The software is working great. But whenever I store the data in a .txt file, it appears "^@^@^@^@^@". Any ideas ?

    ReplyDelete
  18. Hi, I would like to know how to change the code on Rpi to send a string to arduino.

    ReplyDelete
  19. Hi, I would like to know how to change the code on Rpi to send a string to arduino.

    ReplyDelete
    Replies
    1. Here is an example to send strings from the pi to an arduio with an led matrix. http://blog.riyas.org/2013/12/wirelessly-send-strings-to-88-led.html?m=1

      Delete
  20. Hi,
    Thanks for such a helpful article, I able to successful send data from Arduino to Raspberry pi.
    But now I have to establish communication between two Arduino, Please help me out with Arduino Rx code
    http://pastebin.com/FK1mWThG

    ReplyDelete
    Replies
    1. Thanks for the comments

      Here is guide for arduino to arduino. http://blog.riyas.org/2013/12/working-quick-start-guide-for-nrf24l01.html?m=1

      Try the basic sketch in the article to make sure that the pipes and adresses are correct. Then modify it to handle the struct variable. I did it a while ago and didnt get time to write it up. Will post it if i can find it.

      Delete
    2. Thank you very much for your reply :)

      Delete
  21. Arduino 1.6.13 is throwing an error "'fdevopen' was not declared in this scope". Am I missing a library?

    ReplyDelete