Having been a fan of RM95 radios for a while now, like a lot of folks I wanted to integrate them into the Photon world to gain access to easy Internet access. Several folks on this community board have posted their work so I thought I would post mine. My setup is currently:
- A Moteino board with RF95 LoRa radio acting as the server
- A Moteino board with RF95 LoRa radio acting as client #1
- A Photon board with RF95 LoRa radio acting as client #2
Every second, each client sends a packet of fictitious weather data (temp, humidity, wind speed and direction) to the server. To make the prototyping quicker, I use random numbers for temp, humidity and wind. Client 1 sends “N” for wind direction and client 2 sends “E”.
Each time the server receives a packet it subtracts a random value from each numeric field and switches the wind direction (N->S, E->W) and returns the packet. I track RSSI on the server along with time in ms for packet transfer.
I used the standard Particle web IDE and included the RadioHead libraries necessary to make everything work. I’m currently using the RHDatagram manager and will next try the RHReliableDatagram manager and then the RHMesh manager. These are the include files required for RHDatagram:
- RadioHead.h
- RH_RF95.cpp
- RH_RF95.h
- RHDatagram.cpp
- RHDatagram.h
- RHGenericDriver.cpp
- RHGenericDriver.h
- RHGenericSPI.cpp
- RHGenericSPI.h
- RHHardwareSPI.cpp
- RHHardwareSPI.h
- RHReliableDatagram.cpp
- RHReliableDatagram.h
- RHSPIDriver.cpp
- RHSPIDriver.h
You don’t have to change anything in the RadioHead code…just import. Here is the client code running on the Photon:
//
// Last update: 03/25/18
//
/****************************************************/
/* Includes */
/****************************************************/
#include <Particle.h>
#include <RHReliableDatagram.h>
#include <RH_RF95.h>
/****************************************************/
/* Defines */
/****************************************************/
#define MY_ADDRESS 3
#define SERVER_ADDRESS 2
#define TXPWR 5
/****************************************************/
/* Packet structure */
/****************************************************/
#pragma pack(push, 2)
typedef struct WEATHERDATA {
float temp;
float hum;
float windSpeed;
char windDir[2];
};
#pragma pack(pop)
/****************************************************/
/* Globals */
/****************************************************/
WEATHERDATA data;
const float FREQ = 915.0;
RH_RF95 rf95;
RHDatagram manager(rf95, MY_ADDRESS);
ApplicationWatchdog wd(60000, System.reset); // Watchdog timer, will reset system after 60 seconds of inactivity
/****************************************************/
/* setup */
/****************************************************/
void setup(void)
{
Serial.begin(115200);
setupRadio();
}
/****************************************************/
/* loop */
/****************************************************/
void loop(void)
{
unsigned long startMilli,
stopMilli;
data.temp = random(50,95);
data.hum = random(25,75);
data.windSpeed = random(15,30);
strcpy(data.windDir, "E");
Serial.println("=======> Sending temp = " + String(data.temp,1));
Serial.println("=======> Sending hum = " + String(data.hum,1));
Serial.println("=======> Sending wind speed = " + String(data.windSpeed,0));
Serial.println("=======> Sending wind direction = " + String(data.windDir));
startMilli = millis();
if (!manager.sendto((uint8_t *) &data, sizeof(data), SERVER_ADDRESS))
Serial.print("Transmit failed");
rf95.waitPacketSent(100); // wait 100 mSec max for packet to be sent
stopMilli = millis();
Serial.print("Transmission time (mSec) = ");
Serial.println(stopMilli-startMilli);
Serial.println();
startMilli = millis();
if (rf95.waitAvailableTimeout(100)) // wait 100 mSec max for response
{
uint8_t bufLen = sizeof(data);
if (manager.recvfrom((uint8_t *) &data, &bufLen))
{
stopMilli = millis();
Serial.print("Response time (mSec) = ");
Serial.println(stopMilli-startMilli);
if (bufLen == sizeof(data))
{
Serial.println("<======= Received temp = " + String(data.temp,1));
Serial.println("<======= Received hum = " + String(data.hum,1));
Serial.println("<======= Received wind speed = " + String(data.windSpeed,0));
Serial.println("<======= Received wind direction = " + String(data.windDir));
}
else
Serial.println("Incorrect response size");
}
}
else
Serial.println("Timed out waiting for response");
Serial.println();
delay(1000);
}
/****************************************************/
/* setupRadio */
/****************************************************/
void setupRadio(void)
{
if (manager.init())
{
if (!rf95.setFrequency(FREQ))
Serial.println("Unable to set RF95 frequency");
if (!rf95.setModemConfig(RH_RF95::Bw500Cr45Sf128))
Serial.println("Invalid setModemConfig() option");
rf95.setTxPower(TXPWR);
Serial.println("RF95 radio initialized.");
}
else
Serial.println("RF95 radio initialization failed.");
Serial.print("RF95 max message length = ");
Serial.println(rf95.maxMessageLength());
}