Internet of things – Measure environnement data with arduino and push it to the web via Raspberry Pi and NRF24L01

In this post I will complete the idea explained in one of my previous posts.

Here is the idea:

  • First Arduino sensors grab environment data via sensors
  • Then data is sent to a raspberry connected to the web via NRF24L01 – a custom protocol will be needed to achieve this part
  • Raspberry decode data and push it to the web (I use https://thingspeak.com as platform)

Needed Hardware

300px-RaspberryPi

 A Raspberry Pi

 Websitehttp://www.raspberrypi.org/

 Price: less than 50$ (Amazon)

Mine is a B Model

21LtIG91FRL._AA160_

A Atmega 328P with bootloader

 Price: less than 5$ (Amazon)

jpeg-22 NRF24L01 modules

Price: less than $20 (Amazon)

 

Some other components:

Abstract

For this use case we’ll need to be able to have several Arduino with several sensor on each.
Sans titre - copie

The protocol

In order to send data from Arduino to the central Raspberry, I need to define a protocol over NRF24L01. Each sent block will contain:

  • A unique id for the device id: to identify the given arduino
  • Type of data contained into the block type: this type can be composed of several one, e,g, TEMPERAURE | PRESSURE
  • A values table containing values for each previous type: val

Only 32 bytes are available to communicate via NRF24L01. The sent payload will use all bytes:
payload

  • Device id is a 16 char array. Why a long id as this one? Because I want to sent data to https://thingspeak.com and the identifier of a channel (on channel per sensor) is a 16 characters String. It means each device will log data in a given Channel on thingspeak
  • Type is a simple 2 bytes int allowing to send up to 16 different types.
  • 14 bytes are left. So I had to choose if I want to send up to 3 floats (4bytes x 3values = 12) or 7 16-bits integers (7*2bytes = 14 bytes). float are interesting because of the floating point (e,g, 22.3 °C for a temperature) but uses 4 bytes each 🙁 .So I decided to use a int. In order to be able to send floating values, real values will be multiplied by 100 before sending and divided by 100 after reception. This hack allows to send values between -327,68 and 327,67. This range is perfect for real life values (temperature, pressure, humidity)

In terms of code here is the declaration of a payload:

enum TYPES {
  TEMPERATURE   = 1,
  HUMIDITY      = 2,
  CURRENT       = 4,
  LUMINOSITY    = 8,
  PRESSURE      = 16,
};
 
//DATA
typedef struct {
  // id of the device -> max is 16 characters
  char id[16];
  // type of the device -> a simple int
  int16_t type;
  //data
  int16_t val[7];
} Payload;
Payload p;

Principle sample

process

Hardware

Raspberry part

Arduino part

Capture d’écran 2014-06-11 à 19.52.11

 

pinNRF

Raspberry code

The raspberry in in charge to read data sent via NRF24L01 decode it and then send data to internet via ethernet port:

Code can be make by the make file in the project: https://github.com/vdemay/RF24L01

Arduino code

Full project

All the code is available here : https://github.com/vdemay/RF24L01

How to configure ThinkSpeak

  • Create an account on https://thingspeak.com
  • Go to My ChannelThinkSpeak_create_channel
  • Create a new channelthinkspeak_channel
  • Once your channel created, go to API Keys tabthink_speak_api_key
  • Now you can use this key (blurred in the screen shot) to complete arduino code

 Visualization

And here is the result on  ThinkSpeak:

thinkspeak_result

16 Comments

  1. Hello,

    I have a problem, it seems that the arduino and the raspberry doesn’t handle int16_t in a same manner. Have you experienced the same problem ? Thanks

    (Sorry for my english I’m french)

    Reply
      • Thanks to you for the work, expecially the watchdog part is really good!
        I also have not totally clear what this part is doing..
        // Compare receive payload with outBuffer
        if ( ! strcmp(outBuffer, receivePayload) ) {
        rtt = millis() – send_time;
        //Serial.println(“inBuffer –> rtt:”);
        //Serial.println(rtt);
        how do you get send_time?
        thank a lot for answering!

        Reply
  2. Hi Joe.

    Thanks for the pointer: send_time should be initialized here

    if ( radio.write(&p, sizeof(p)) ) {
    //Serial.println(“Send successful\n\r”);
    send_time = millis()
    }

    I’m going to change the code.

    Thanks

    Reply
  3. So I wonder How long the battery last?

    I’m doing the same thing than you but I got a problem with the DHT22. It stop working when the power is below 2.7V. Then I decide to use 4.5V instead. I did have to change the brew detection to 1.7V instead of 2.7V. I’m using the arduino pro mini and I removed the regulator and the resistor for power led. (The cost was pratically the same to buy an arduino pro mini than to order the I.C. itself). Granted the I.C. is cheaper but with the shipping cost it was higher.

    Reply
  4. Great post! thanks for sharing your thoughts.

    Just a simple note, in the first section (The Protocol), in the last point you said that “This hack allow to send values between -327,68 and 327,68” actually this should only values between [-327,68 and 327,67].

    Reply
  5. bnj, je vous remercie pour vos efforts
    j’ai un problème au niveau de réception et je voudrai si vous pouvez m’aide à le résoudre
    j’ai pris le même fonctions send et recive avec quelle-que modification mais j’ai rien reçu
    partie modifie code raspb :
    if ((p.type & SOUND) == SOUND) {
    strcat(outBuffer,”&1=”);
    sprintf(temp, “%d”, p.val[val++]);
    strcat(outBuffer, temp);
    }
    if ((p.type & MOVEMENT) == MOVEMENT ) {
    strcat(outBuffer,”&2=”);
    sprintf(temp , “%d”, p.val[val++]);
    strcat(outBuffer, temp);
    }
    if ((p.type & LUMINOSIRTY) == LUMINOSIRTY) {
    strcat(outBuffer,”&3=”);
    sprintf(temp, “%d”, p.val[val++]);
    strcat(outBuffer, temp);
    }
    if ((p.type & TEMPERATURE ) == TEMPERATURE ) {
    strcat(outBuffer,”&4=”);
    sprintf(temp, “%d”, p.val[val++]);
    strcat(outBuffer, temp);
    }
    if ((p.type & HUMIDITY) == HUMIDITY) {
    strcat(outBuffer,”&6=”);
    sprintf(temp, “%d”, p.val[val++]);
    strcat(outBuffer, temp);
    }

    arduino

    void sendOverRadio(int timer, long period) {
    if (!waitFor(timer,period)) return;
    //power on radio
    radio.powerUp();
    //prepare
    uint8_t data1 = 0;
    bool timeout=0;
    uint16_t nodeID = pipes[0] & 0xff;
    char outBuffer[32]=””;
    unsigned long send_time, rtt = 0;
    // Stop listening and write to radio
    radio.stopListening();
    // Send to hub
    if ( radio.write(&p, sizeof(p)) ) {
    if (DEBUG) Serial.println(“Send successful\n\r”);
    send_time = millis();
    }else { if (DEBUG) Serial.println(“Send failed\n\r”);}
    //wait response
    radio.startListening();
    while ( radio.available() && !timeout ) {
    uint8_t len = radio.getDynamicPayloadSize();
    radio.read( receivePayload, len);
    receivePayload[len] = 0;
    // Compare receive payload with outBuffer
    if ( ! strcmp(outBuffer, receivePayload) ) {
    rtt = millis() – send_time;
    if (DEBUG) Serial.println(“inBuffer –> rtt:”);
    if (DEBUG) Serial.println(rtt);
    }
    // Check for timeout and exit the while loop
    if ( millis() – send_time > 255 ) {
    Serial.println(“Timeout!!!”);
    timeout = 1;
    }
    }
    }

    Reply

Leave a Reply to akram Cancel reply