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 as platform)

Needed Hardware


 A Raspberry Pi


 Price: less than 50$ (Amazon)

Mine is a B Model


A Atmega 328P with bootloader

 Price: less than 5$ (Amazon)

jpeg-22 NRF24L01 modules

Price: less than $20 (Amazon)


Some other components:


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:

  • Device id is a 16 char array. Why a long id as this one? Because I want to sent data to 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 {
  HUMIDITY      = 2,
  CURRENT       = 4,
  LUMINOSITY    = 8,
  PRESSURE      = 16,
typedef struct {
  // id of the device -> max is 16 characters
  char id[16];
  // type of the device -> a simple int
  int16_t type;
  int16_t val[7];
} Payload;
Payload p;

Principle sample



Raspberry part

Arduino part

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



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:

Arduino code

Full project

All the code is available here :

How to configure ThinkSpeak

  • Create an account on
  • 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


And here is the result on  ThinkSpeak:



  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)

      • 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:”);
        how do you get send_time?
        thank a lot for answering!

  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.


  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.

  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].

  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) {
    sprintf(temp, “%d”, p.val[val++]);
    strcat(outBuffer, temp);
    if ((p.type & MOVEMENT) == MOVEMENT ) {
    sprintf(temp , “%d”, p.val[val++]);
    strcat(outBuffer, temp);
    if ((p.type & LUMINOSIRTY) == LUMINOSIRTY) {
    sprintf(temp, “%d”, p.val[val++]);
    strcat(outBuffer, temp);
    if ((p.type & TEMPERATURE ) == TEMPERATURE ) {
    sprintf(temp, “%d”, p.val[val++]);
    strcat(outBuffer, temp);
    if ((p.type & HUMIDITY) == HUMIDITY) {
    sprintf(temp, “%d”, p.val[val++]);
    strcat(outBuffer, temp);


    void sendOverRadio(int timer, long period) {
    if (!waitFor(timer,period)) return;
    //power on radio
    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
    // 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
    while ( radio.available() && !timeout ) {
    uint8_t len = radio.getDynamicPayloadSize(); 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 ) {
    timeout = 1;


Leave a Reply to Sabi Cancel reply