Wireless control of Arduino with RPi

I currently have a Raspberry Pi logging temperatures to a database received from two Arduinos sending their data with nRF24L01 modules. I want to extend the system so the Pi can control other Arduinos using a web interface on the Pi but I'm not sure how to implement it.

I have my TempReceiver program running on the Pi continuously listening for data. I'm not sure where to go from there. Do I interact with that program somehow? Run another program when the web interface requests something? Can I run another program to send something to an Arduino while the receiver program is also running?

Can you post the scripts how you collect data from multiple transmiters, please?

Yeah, no problem. The code on the Arduino is pretty straight forward. Each device has an ID, takes the temp and sends it to node 0.

The code on the Pi is a bit of a cobbled together mess. Receives the data, works out the ID, opens a file to write to but also saves it to a sqlite database and outputs it to the screen.

Arduino code:

#include <OneWire.h>
#include <DallasTemperature.h>
#include "LowPower.h"
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>


//Device specific stuff
int device=2;
const uint16_t this_node = 02;

DeviceAddress Probe01 = {
  0x28, 0xFF, 0x1E, 0x2A, 0x68, 0x14, 0x04, 0xCB
};
//End device specific stuff

int led=13;
int battery=A0;




#define ONE_WIRE_BUS 2





OneWire oneWire(ONE_WIRE_BUS);


DallasTemperature sensors(&oneWire);



RF24 radio(9,10);                    // nRF24L01(+) radio attached using Getting Started board 

RF24Network network(radio);          // Network uses that radio

const uint16_t other_node = 00;       // Address of the other node in Octal format


struct payload_t {                  // Structure of our payload
  float temp;
  int voltage;
  int deviceNum;
};

int counter=1;

void setup(void)
{
  sensors.begin();
  sensors.setResolution(12);
  SPI.begin();
  radio.begin();
  network.begin(/*channel*/ 90, /*node address*/ this_node);
  pinMode(led, OUTPUT);

}

void loop() {
  if (counter==8)
  {
    digitalWrite(led, HIGH);
   
    sensors.requestTemperatures();
    float temp=sensors.getTempC(Probe01);
    int battInt=0;
    battInt=analogRead(battery);
    battInt=analogRead(battery);
   
    if (temp<80)
    {
      radio.powerUp();
      network.update();
      payload_t payload = { 
        temp,battInt, device};
    
      RF24NetworkHeader header(/*to node*/ other_node);
      bool ok = network.write(header,&payload,sizeof(payload));
       //if (ok)
       //   Serial.println("ok.");
       // else
       //   Serial.println("failed.");
      radio.powerDown();
    }
    counter=1;
    digitalWrite(led, LOW);
  }
  else
  {
    counter++;
  }


  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); 
}

Raspberry Pi code:

#include <cstdlib>
#include <dirent.h>
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <signal.h>
#include <RF24/RF24.h>
#include <RF24Network/RF24Network.h>
#include <ctime>
#include <stdio.h>
#include <time.h>
#include <sstream>
#include <sys/time.h>

int8_t volatile keepRunning = 1;

// Pointer to Sqlite3 DB - used to access DB when open
sqlite3 *db = NULL;
// Path to DB file - same dir as this program's executable
char *dbPath = "/var/www/sqlTemplog.db";
// DB Statement handle - used to run SQL statements
sqlite3_stmt *stmt = NULL;


FILE *f;

int counter=1;

int8_t recordTemp(int devID, double tempC) {
 char *sql = "INSERT INTO temps( id, timestamp, temp) VALUES(?,datetime('now'), ?)";
 if(!sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL)== SQLITE_OK)
 {
        fprintf(stderr, "MEhhdfsd: %s\n", sqlite3_errmsg(db));
    }
 
     sqlite3_bind_int(stmt, 1, devID);
     sqlite3_bind_double(stmt, 2, tempC);
     sqlite3_step(stmt);  // Run SQL INSERT
     sqlite3_reset(stmt); // Clear statement handle for next use
 return 0;
}	



void intHandler() {
    printf("\nStopping...\n");
    keepRunning = 0;
}


//struct dataStruct{

 // unsigned long ms;
 // unsigned long counter;
 // float temp;

//}myData;

/**
 * g++ -L/usr/lib main.cc -I/usr/include -o main -lrrd
 **/
//using namespace std;

// CE Pin, CSN Pin, SPI Speed

// Setup for GPIO 22 CE and GPIO 25 CSN with SPI Speed @ 1Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_18, BCM2835_SPI_SPEED_1MHZ);

// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ); 

// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ);  

RF24Network network(radio);

// Address of our node in Octal format
const uint16_t this_node = 00;

// Address of the other node in Octal format (01,021, etc)
const uint16_t other_node = 01;
const uint16_t clock_node = 03;

//const unsigned long interval = 2000; //ms  // How often to send 'hello world to the other unit

unsigned long last_sent;             // When did we last send?
unsigned long packets_sent;          // How many have we sent already


struct payload_t {                  // Structure of our payload
  float temp;
  uint16_t voltage;
  uint16_t deviceNum;
};

struct payload_temp {
	float temp;
};

struct payload_time{
	int hours;
	int minutes;
	int seconds;
};

struct payload_voltage{
	uint16_t volts;
	};

int main(int argc, char** argv) 
{
	int rc = sqlite3_open(dbPath, &db);
	 // If rc is not 0, there was an error
	 if(rc)
	{
		fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
		exit(0);
	}
		// Refer to RF24.h or nRF24L01 DS for settings
	
	radio.begin();
	//radio.setDataRate(RF24_250KBPS);
	delay(5);
	network.begin(/*channel*/ 90, /*node address*/ this_node);
	radio.printDetails();

	//uint16_t deviceNumber;

		
	while(keepRunning)
	{

		network.update();
		while ( network.available() ) 
		{     

			
			RF24NetworkHeader header;
			network.peek (header);
			
			{
				payload_t payload;
				network.read(header,&payload,sizeof(payload));
				float battVolts = payload.voltage * 0.0033248;


				if (payload.voltage>0)
					printf("Received payload # %i at %f %fV ",payload.deviceNum,payload.temp, battVolts);
				else
					printf("Received payload # %i at %f \n", payload.deviceNum, payload.temp);
				if (payload.deviceNum==1)
					f = fopen( "/home/pi/temp1.log", "a");
				else if (payload.deviceNum==2)
					f = fopen("/home/pi/temp2.log", "a");
				else
					f=fopen("/home/pi/volts.log", "a");
				recordTemp(payload.deviceNum, payload.temp);


				timeval curTime;
				gettimeofday(&curTime, NULL);

				char TimeString[128];

				strftime(TimeString, 80, "%Y-%m-%d %H:%M:%S", localtime(&curTime.tv_sec));

				char deviceNum[1];
				sprintf(deviceNum, "%i", payload.deviceNum);
				fprintf(f, deviceNum);
				fprintf(f, ",");

				char temp[4];
				sprintf(temp, "%f", payload.temp);
				fprintf(f, TimeString);
				fprintf(f, ",");
				fprintf(f, temp);


				if (payload.voltage>0)
				{
				fprintf(f, ",");
					char volts[4];
					sprintf(volts, "%f", battVolts);
					fprintf(f, volts);
					//printf(payload.voltage);
				}

				fprintf(f, "\r\n");
				fclose(f);
				//printf("Close file\n");
				//if (payload.deviceNum==1)counter=1;
				
				if (payload.deviceNum==2)
				{
					float tempFF=payload.temp;
					payload_temp payload = { tempFF };
					RF24NetworkHeader header(/*to node*/ clock_node, 'T');
					bool ok = network.write(header,&payload,sizeof(payload));
					if (ok)
						printf(" - sent.\n");
					else
						printf("\n");
				}
				
			}
		}
		
		
		usleep(100000);
		//fclose(pFile);
		//counter=counter+1;
	}
	sqlite3_close(db);
	return 0;
}

I’ve got v0.2 of my wireless board up and running. Now clocked at 4MHz so I can run it down to 1.8V. Switching the power to the DS18B20 and radio through the digital pins, and the temp sensor powered by a step up regulator.

Some optimisations to the code, only sends the temp if it has changed, or if 10 minutes has passed.

The only problem with this setup is switching the temperature sensor on and off requires a delay when it first starts up so it can read the temp. So it’s running for almost 1 second every time it wakes up.

ChrisHigs:
I've got v0.2 of my wireless board up and running. Now clocked at 4MHz so I can run it down to 1.8V. Switching the power to the DS18B20 and radio through the digital pins, and the temp sensor powered by a step up regulator.

Some optimisations to the code, only sends the temp if it has changed, or if 10 minutes has passed.

The only problem with this setup is switching the temperature sensor on and off requires a delay when it first starts up so it can read the temp. So it's running for almost 1 second every time it wakes up.

Could you please upload your revised code and a few details of the Pi setup.
I have a couple of the NRF's, several Pi's and lots of Arduinos.
Does the Pi code you provided need compiling on the Pi and if so could you provide the full command line required to do this?

Made some more adjustments. Using the 3.3V step up to power it all again now. I thought that was causing my battery problems but it was something else.

The Arduino now shuts down when the sensor is converting the temp, saves a bit of power because it was using delay() before.

I've also got a red LED which I power on for a bit if the sensor's values are out of range or it's not connected.

I'll try and remember what I did with the pi, tidy up the code a bit and try and post it later.

Ok, here is my Pi and Arduino software.

The Pi has a SQLite database that the temperature and time are saved to.

g++ -Ofast -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -lsqlite3 -Wall -I../ -lrf24-bcm -lrf24network

is what the Makefile that comes with the RF24Network examples uses to compile so I used that for my program and added the sqlite3.

The Arduino is switching off the radio and temp sensor, took a while to work out how to get both of those working properly when they powered back on.

And it is using ~4uA when sleeping.

Edited the TempReceiver.cpp to change to “const char” to remove some of the compile errors.

transmitterNode2.ino (4.03 KB)

TempReceiver.cpp (3.57 KB)

Actually I haven't tested the Arduino code. I've simplified and refactored it so there is a chance it doesn't work but it should.

I've finally managed to work out a way of doing this. I asked over at the RPi forums and someone suggested Civetweb. It's a C++ embedded server based on Mongoose.

I've made a test update to my temp receiver, added a button to a web page to send a package to my Uno (which I haven't plugged in yet) and it seems to be working. As the Uno side isn't setup yet it says "Unable to send payload" on the page after pressing the button. Have to test it properly soon.

Looks like I should be able to sort out what I want with this though :slight_smile:

I’m finally getting somewhere, Working on the code for this and it’s turned out to be more complicated than I was expecting.

I can now switch an LED on my Uno from a web interface and get it’s current state. Shouldn’t take too much to connect it to my relay now.

And it works :smiley:

I now have a web interface on my Pi from which I can turn my heating and hot water on and off. I can also set them to come on for 15/30/60 minutes.

And it’s all working while still receiving data from my wireless sensors. Awesome. More work than I was expecting for that.

And here is my interface along with the temperature graph. Need to add some more sensors for other rooms and outside when I get a chance to build some more.

ChrisHigs:
And here is my interface along with the temperature graph. Need to add some more sensors for other rooms and outside when I get a chance to build some more.

Looking good Chris.

Looking a bit better with some CSS now.