Particle Photon / Electron + RFN95W Long Range Radio

Yes, it’s working now.

I did have to change the D2----------->DIO1 To D2----------->DIO0 to get code to run.

I also had a bad jumper wire on the MISO line which I fixed.

Excited to see this working so I can start to build out a sensor hub with the Photon or Electron. I’ll include it here when I have something.

I’ll test the range with this setup now also and hopefully it works further than 10 feet :slight_smile:

@luisgcu I had to hop in the car and do a quick test of the Reliable Datagram using your Modem settings to see if it actually worked now or not.

I’m happy to announce that I am getting 1 mile communication range using the crude 3 inch wire antennas. So I’m sure the better antennas will help also.

I just removed a RFM95 module from one of my Adafruit LORA boards since I already had it. It’s not pretty but it proves it works to me. I’m impressed with the range for such a cheap $10 radio
module and simple wire antennas.

These would allow people to keep the Photon near a WiFi HotSpot and AC power while getting their sensors into locations where the Photon will work due to lack of Wif there or because of the Photon’s higher power requirments when running on batteries.

I can say the RFM95 module provides the same range as the $60 XBee 900 Pro HP modules with the high gain rubber ducky antennas.

1 Like

@rwb That is the correct connection.. sometimes I have wear glasses..:slight_smile:

Photon RFM96
D2----------->DIO0
A2----------->NSS
A3----------->SCK
A4----------->MISO
A5----------->MOSI
GND--------->GND
3V3---------->3.3V IN

I’ll promise to get some time and share GPS tracking project that I did using moteinos ( you may use adafruit Lora) with GPS sending its position to photon acting as hub… then latitude and longitude posted on world-map node on Node-red, that way is easy to track Lora modules range.

We may be able to use the new Particle to Google Maps integration to just forward the GPS data directly to Google Maps for location tracking and mapping.

Have not checked it out yet but it should be easy since it just takes GPS data and forwards it to Google.

I’m going to design a custom Photon / Electron Pcb for the Lora radios in the near future.

1 Like

I updated the Reliable Datagram Code for the Photon & Adafruit Feather LoRa module to include the following:

  • RSSI signal strength for each message received.
  • LED Flash Indicators to detect if the message was successful or not.
  • Added Message Counter so each message sent has a number attached that increases every message.

Photon Code -

//PHOTON
// this the client running on photon
#include <RHReliableDatagram.h>
#include <RH_RF95.h>
//#include <SPI.h>
SYSTEM_MODE(SEMI_AUTOMATIC);

#define CLIENT_ADDRESS 1
#define SERVER_ADDRESS 2

const int ledPin = D7;     // D7 has an LED

// Singleton instance of the radio driver
RH_RF95 driver;  //(A2,D2)-->you don't nee set this
//RH_RF95 rf95(5, 2); // Rocket Scream Mini Ultra Pro with the RFM95W

// Class to manage message delivery and receipt, using the driver declared above
RHReliableDatagram manager(driver, CLIENT_ADDRESS);

// Need this on Arduino Zero with SerialUSB port (eg RocketScream Mini Ultra Pro)
//#define Serial SerialUSB

void setup()
{
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);


  Serial.begin(9600);

  if (!manager.init())
  Serial.println("init failed");
  driver.setTxPower(23, false);
  driver.setFrequency(915.0);  // hay que setear frecuencia para los rfm96 915
  delay(5000);
  Serial.println("..this is the Photon as Client Radio");
}

//uint8_t data[] = "Hello World #      ";
// Dont put this on the stack:
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];

int16_t packetnum = 0;  // packet counter, we increment per xmission

void loop()
{

  Serial.println("Sending to Server Base Station");
  // Send a message to manager_server basestation.

  char radiopacket[20] = "Hello World #      ";
  itoa(packetnum++, radiopacket+13, 10);
  Serial.print("Transmitting > "); Serial.println(radiopacket);
  radiopacket[19] = 0;
  Serial.println("");

  if (manager.sendtoWait((uint8_t *)radiopacket, sizeof(radiopacket), SERVER_ADDRESS))
  {
    // Now wait for a reply from the server base station.
    uint8_t len = sizeof(buf);
    uint8_t from;

    Serial.println("Waiting for reply..."); delay(10);

    if (manager.recvfromAckTimeout(buf, &len, 2000, &from))
    {
      //Flash D7 LED on Photon if Received Reply
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);

      Serial.print("Got reply from Server Base Station 0x");
      Serial.print(from, HEX);
      Serial.print(": ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(driver.lastRssi(), DEC);

      Serial.println();
      Serial.println();

    }
    else
    {

      Serial.println("No reply from Server Base Station?");

      //Flash D7 LED on Photon if No Reply From Server Base Station.
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
    }
  }
  else{
    Serial.println("sendtoWait failed");
    digitalWrite(ledPin, HIGH); //Flash D7 LED on Photon if SendtoWait Failed
    delay(250);
    digitalWrite(ledPin, LOW);
    delay(250);
    digitalWrite(ledPin, HIGH);
    delay(250);
    digitalWrite(ledPin, LOW);
    delay(250);
    digitalWrite(ledPin, HIGH);
    delay(250);
    digitalWrite(ledPin, LOW);
    delay(250);
    digitalWrite(ledPin, HIGH);
    delay(250);
    digitalWrite(ledPin, LOW);
    }

  delay(5000);
}

Code for the Adafruit 32u4 Feather + LoRa RF95 915mhz model -

// rf95_reliable_datagram_server.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple addressed, reliable messaging server
// with the RHReliableDatagram class, using the RH_RF95 driver to control a RF95 radio.
// It is designed to work with the other example rf95_reliable_datagram_client
// Tested with Anarduino MiniWirelessLoRa, Rocket Scream Mini Ultra Pro with the RFM95W 

#include <RHReliableDatagram.h>
#include <RH_RF95.h>
#include <SPI.h>

/* for feather32u4 */
#define RFM95_CS 8
#define RFM95_RST 4
#define RFM95_INT 7

#define CLIENT_ADDRESS 1
#define SERVER_ADDRESS 2

// Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);
//RH_RF95 driver(5, 2); // Rocket Scream Mini Ultra Pro with the RFM95W

#define RF95_FREQ 915.0

// Class to manage message delivery and receipt, using the driver declared above
RHReliableDatagram manager(rf95, SERVER_ADDRESS);

// Blinky on receipt
#define LED 13

void setup() 
{
  pinMode(LED, OUTPUT);
  pinMode(RFM95_RST, OUTPUT);
  digitalWrite(RFM95_RST, HIGH);

  Serial.begin(9600);
  delay(100);
  //while (!Serial) ; // Wait for serial port to be available

  Serial.println("Feather LoRa TX Test!");
 // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);
  

  if (!manager.init())
    Serial.println("init failed"); 
   rf95.setTxPower(10, false);
   rf95.setFrequency(915.0);
  Serial.println("..this is the Adafuit Feather LoRa as server +RFM95 @915mhz");
  
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
    
  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 
  // you can set transmitter powers from 5 to 23 dBm:
   //driver.setTxPower(23, false);
  
  // You can optionally require this module to wait until Channel Activity
  // Detection shows no activity on the channel before transmitting by setting
  // the CAD timeout to non-zero:
  // driver.setCADTimeout(10000);
}

uint8_t data[] = "And hello back to you";
// Dont put this on the stack:
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];


void loop()
{
  if (manager.available())
  {
    // Wait for a message addressed to us from the client
    uint8_t len = sizeof(buf);
    uint8_t from;
    if (manager.recvfromAck(buf, &len, &from))
    {
      Serial.print("got request from : 0x");
      Serial.print(from, HEX);
      Serial.print(": ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(rf95.lastRssi(), DEC);
      Serial.println();
      digitalWrite(LED, HIGH); //Flash LED 2 times to indicate received message. 
      delay(250);
      digitalWrite(LED, LOW);
      delay(250);
      digitalWrite(LED, HIGH);
      delay(250);
      digitalWrite(LED, LOW);
      delay(250);
      
      // Send a reply back to the originator client
      if (!manager.sendtoWait(data, sizeof(data), from))
        Serial.println("sendtoWait failed");
        
        
    }
  }
}


2 Likes

@ScruffR @peekay123 @luisgcu

I plan on setting up a network below where WiFi access is not available or reliable so I want to send status info from the Client RFM95w radios to the Server RFM95w radio that will have reliable WiFi access.

I have the demo code for these radios and the Photon working reliably but now I need to modify it so when the Server radio / Photon receives a status update from one of the clients the received data is pushed into a variable or array for each separate radio.

Once I have the client data saved in a variable I can push it to the web and or Update a connected LCD display.

The code I’m running on the Photon server is pretty simple:

uint8_t data[] = "And hello back to you";
// Dont put this on the stack:
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];

void loop()
{
  if (manager.available())
  {
    // Wait for a message addressed to us from the client
    uint8_t len = sizeof(buf);
    uint8_t from;
    if (manager.recvfromAck(buf, &len, &from))
    {
      Serial.print("got request from : 0x");
      Serial.print(from, HEX);
      Serial.print(": ");
      Serial.println((char*)buf);

      // Send a reply back to the originator client
      if (!manager.sendtoWait(data, sizeof(data), from))
        Serial.println("sendtoWait failed");
    }
  }
}

The code that the Photon / Client runs is also pretty simple:

uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];

uint32_t packetnum = 0;  // packet counter, we increment per xmission

void loop()
{

  Serial.println("Sending to Server Base Station");
  // Send a message to manager_server basestation.

  char radiopacket[20] = "Hello World #      ";
  itoa(packetnum++, radiopacket+13, 10);
  Serial.print("Transmitting > "); Serial.println(radiopacket);
  radiopacket[19] = 0;
  Serial.println("");

  if (manager.sendtoWait((uint8_t *)radiopacket, sizeof(radiopacket), SERVER_ADDRESS))
  {
    // Now wait for a reply from the server base station.
    uint8_t len = sizeof(buf);
    uint8_t from;

    Serial.println("Waiting for reply..."); delay(10);

    if (manager.recvfromAckTimeout(buf, &len, 2000, &from))
    {
      //Flash D7 LED on Photon if Received Reply
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);

      Serial.print("Got reply from Server Base Station 0x");
      Serial.print(from, HEX);
      Serial.print(": ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(driver.lastRssi(), DEC);

      Serial.println();
      Serial.println();

    }
    else
    {

      Serial.println("No reply from Server Base Station?");

      //Flash D7 LED on Photon if No Reply From Server Base Station.
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
    }
  }
  else{
    Serial.println("sendtoWait failed");
    digitalWrite(ledPin, HIGH); //Flash D7 LED on Photon if SendtoWait Failed
    delay(150);
    digitalWrite(ledPin, LOW);
    delay(150);
    digitalWrite(ledPin, HIGH);
    delay(150);
    digitalWrite(ledPin, LOW);
    delay(150);
    digitalWrite(ledPin, HIGH);
    delay(150);
    digitalWrite(ledPin, LOW);
    delay(150);
    digitalWrite(ledPin, HIGH);
    delay(150);
    digitalWrite(ledPin, LOW);
    }

  delay(5000);
}

I’m wondering if I can get some help on how to restructure the Client and Server code so it’s flexible enough to handle an unknown number of clients which can range from 1-100 clients.

If each client has it’s own ID# it sends along with it’s the status info I need the Photon to create a data Array for that radio ID# and updates and overwrites the previous data every time it receives a new update.

For example, let’s say each client sends this info:

  • Device Serial ID#
  • Battery SOC
  • Battery Voltage
  • Heading 0-360 Degrees
  • Tilt Degrees 0-90 Degrees
  • Wattage 0-360w
  • Voltage 0-80v

I need help on how to package that data before sending it out and then parsing it once received by the server radio.

I guess this type of setup could be used to push any sensor data from mutiple radios to a web connected Photon or Electron.

Any help with this is apperciated :slight_smile:

2 Likes

@luisgcu Can you share your Particle - RFM95 - GPS sensor code that you were talking about sharing?

I’m curious to see how you’re processing the GPS data when the Server radio receives it.

hi @RWB I will try to do during the day.
in your previous post why do you want to use photon on for the clients? if those nodes are not going to be wifi connected you may use just arduino, for those cases I use Moteino that are just fine… the problem is instead of using the RhReliableDatagram, you must use the RHMesh and it take a lot of dynamic memory when combined with another library, if that is the case then is good reason then to use photon for the clients. other variant is to use Moteino Mega, which has lot of IO, but is more expensive than photon.
by the way one question that you maybe already explored.
How stop photon looking for wifi connection? I meant my photon wont do anything within the program still WiFi is connected.

@luisgcu, take a look at system modes:

https://docs.particle.io/reference/firmware/photon/#system-modes

Also look at system thread:

https://docs.particle.io/reference/firmware/photon/#system-thread

@peekay123 thanks you… I see how it works! particle is really awesome … it make things easier…

here we go @RWB this sample code if very far from be perfect and efficient … but it works.
Particle photon server side.
I am reading once again your previous request and I am not sure if the below what you really need…

//This is the server running on PArticle Photon

#include <RHMesh.h>
#include <RH_RF95.h>
#define SERVER_ADDRESS 1

char publishString[100];

RH_RF95 driver;//(10,2);  //moteino mega
//RHReliableDatagram manager(driver, CLIENT_ADDRESS);
RHMesh manager(driver, SERVER_ADDRESS);
#define DELAY_MS  40
#define Doutput7 7  //D7 on Photon

int ledState = HIGH;

//put here coordinates of your home address
const float Mylatitude  = 29.53443 ;  //fake 
const float Mylongitude =-81.5555 ;

//data struct that hold the data from the cliente via Rfm96
struct Gpsdata{
 float  latitude;    // I had problem with ESP8266 declaring Lat and long as float, So I have to use DOUBLE. 
 float longitude;
  //int        data;
};
Gpsdata MyGpsdata;

// Global variables
char sendBuf[256];


bool InputTrigger;

uint8_t*GpsPayload;
//int gps_on(String  command);

void setup() {

 pinMode(Doutput7,OUTPUT); //blue led
 digitalWrite(Doutput7,HIGH);
 delay(DELAY_MS);
 digitalWrite(Doutput7,LOW);
 delay(DELAY_MS);
 digitalWrite(Doutput7,HIGH);
 delay(DELAY_MS);
 digitalWrite(Doutput7,LOW);
 delay(DELAY_MS);


 Serial.begin(9600);
// while (!Serial) {
  //  ; // wait for serial port to connect. Needed for Leonardo only
//  }
///delay(10000);
  if (!manager.init())
  Particle.publish("init Failed!");
    Serial.println("init failed");
    Serial.println("GPS_TRACKER_SERVER");
    Particle.publish("GPS_TRACKER_SERVER");
    driver.setTxPower(10, false);
   driver.setFrequency(915.0);  //Set Freuency rfm96 915
   GpsPayload =(uint8_t*)(&MyGpsdata);

}


void loop()
 {

   if (manager.available())
       {
          uint8_t len = sizeof( MyGpsdata);
          uint8_t from;
                  if (manager.recvfromAckTimeout(GpsPayload, &len, 3000, &from))

                   {

                   float distances= calc_dist( Mylatitude,  Mylongitude,  MyGpsdata.latitude,  MyGpsdata.longitude);
                  
                    int rssi= driver.lastRssi();
                    sprintf(publishString, "{\"From_mobile\":%d, \"Latitude\":%.6f, \"Longitude\":%.6f, \"RSSI\":%d, \"Dist\":%.2f}",from, MyGpsdata.latitude, MyGpsdata.longitude, rssi, distances );

                    Spark.publish("GPSDATA",publishString);
                    Serial.println(F("Latitude,    Longitude,  rssi,  from,  Distance"));
                    Serial.print(MyGpsdata.latitude,6);
                    Serial.print(",  ");
                    //Particle.publish("Longitude", String(MyGpsdata.longitude,6));
                    Serial.print(MyGpsdata.longitude,6);
                    Serial.print(",  ");
                    Serial.print(driver.lastRssi(), DEC);
                    Serial.print(",    ");
                    Serial.print(from);
                    Serial.print(",    ");
                    Serial.print(distances,2);
                    Serial.println();
                    digitalWrite(Doutput7,HIGH);
                    delay(DELAY_MS);
                    digitalWrite(Doutput7,LOW);
                  
                   }
           }


 }

/*************************************************************************
 * //Function to calculate the distance between two waypoints
 *************************************************************************/
float calc_dist(float flat1, float flon1, float flat2, float flon2)
{
float dist_calc=0;
float dist_calc2=0;
float diflat=0;
float diflon=0;

//I've to spplit all the calculation in several steps. If i try to do it in a single line the arduino will explode.
diflat=radians(flat2-flat1);
flat1=radians(flat1);
flat2=radians(flat2);
diflon=radians((flon2)-(flon1));

dist_calc = (sin(diflat/2.0)*sin(diflat/2.0));
dist_calc2= cos(flat1);
dist_calc2*=cos(flat2);
dist_calc2*=sin(diflon/2.0);
dist_calc2*=sin(diflon/2.0);
dist_calc +=dist_calc2;

dist_calc=(2*atan2(sqrt(dist_calc),sqrt(1.0-dist_calc)));

dist_calc*=6371000.0; //Converting to meters
//Serial.println(dist_calc);
return dist_calc;
}


============================================
the next is the Client, I use Moteino, so you need to adapt the code & libraries for particle photon.

============================================

//GPS client ID 2
#include <RHMesh.h>
#include <RH_RF95.h>
#include <SPI.h>
#define SERVER_ADDRESS 1
#define CLIENT2_ADDRESS 2
#define CLIENT3_ADDRESS 3
#include <TinyGPS++.h>
#include <SoftwareSerial.h>

static const int RXPin = 3, TXPin = 14;
static const uint32_t GPSBaud = 9600;

// Create a TinyGPS++ object called "gps"
TinyGPSPlus gps;

// Create a software serial port called "gpsSerial"
SoftwareSerial ss(RXPin, TXPin);
RH_RF95 driver;   //moteino

RHMesh manager(driver, CLIENT2_ADDRESS);
#define Douput9  9  //
const int  SendInterval=  60;  //
int SendIntervalCount = 0;
int ledState = HIGH;
int replicar1 =0; 

double oldlat1 ;
double oldlong1;
    

  struct Gpsdata
  {
   float latitude;  // I had problem with ESP8266 when defining latitude and longitude as float, I had to change that to DOUBLE
   float longitude;
   //int otherdata;
  };
Gpsdata MyGpsdata;



//bool InputTrigger;
uint8_t*GpsPayload;

unsigned long previousMillis = 0;        // will store last time LED was updated

void setup() {

 pinMode(Douput9,OUTPUT);
 
 digitalWrite(Douput9,HIGH);
 delay(2000);
 digitalWrite(Douput9,LOW);
 
 Serial.begin(115200);      //com 1 en el arduino
 ss.begin(GPSBaud);
  if (!manager.init())
    Serial.println(F("RFM_96 init failed"));
    delay(1000);
    Serial.println(F("GPS SENDER-915-CLIENT #2"));
    driver.setTxPower(5, false);  //5dbm---> 1.5km
    driver.setFrequency(915.0);  // Set frecuency 

  GpsPayload = (uint8_t*)(&MyGpsdata);

    
}
  
void loop() {

 while (ss.available() > 0)
       if (gps.encode(ss.read()))
     {
        SendIntervalCount++;
        if(SendIntervalCount > SendInterval)  //check gps data based on interval given by counting 
        {
             SendIntervalCount = 0;     
                  
            if (gps.location.isValid())  //check if GPS location is valid
           
            {
              //Gps_sending();
              //READ  current latitude and longidute
               double lat1 =gps.location.lat();
               double lon1 =gps.location.lng();
               //calculate the distance bewten current pos and previous position
               double distance = gps.distanceBetween(lat1,lon1,oldlat1,oldlong1);
               Serial.print("Distance:  ");
               Serial.println(distance,2);
               //only goin to  send GPS position to server is distance is greater than a value meters that one consider as apropiate
               // for my test  i set that value =2meters, 
               if  (distance >= 2) {
                 oldlat1=lat1;
                 oldlong1=lon1;
                Serial.println("Sending data to Server:"); 
                Gps_sending();
               }
       
            }
            else
            {
              //no gps fix blue led blink
               Serial.println(F("Location not valid"));
             //  Blink(Doutput2, 20, 4); //blink LED 3 times, 40ms between blinks
           
            }
            
        }
     }
 
}


void Gps_sending(){
  //feed the struture with current gps data
  MyGpsdata.latitude  = gps.location.lat();
  MyGpsdata.longitude = gps.location.lng();
//  MyGpsdata.data =2345;
   unsigned long now1 =millis();
   //uint8_t from;
  if (manager.sendtoWait(GpsPayload, sizeof(MyGpsdata), SERVER_ADDRESS) == RH_ROUTER_ERROR_NONE)
       {
       unsigned long now2=millis();
       unsigned long  timeflight= now2-now1;
       //   Serial.println(F("Mensaje sent OK "));
       //   Serial.print(F("delay:=  "));
       //   Serial.print(timeflight);
       //   Serial.print("  : Last Rssi: ");
       //   Serial.println(driver.lastRssi(), DEC);
       //   Blink(Doutput1, 20, 4); //blink LED 3 times, 40ms between blinks
        
   
    }
    else 
    {
      Serial.println(F("Mensaje has  failed"));
     // Serial.print(F("Latitude: "));
     // Blink(Doutput3, 30, 4); //blink LED 3 times, 40ms between blinks      
    
    }

 
}


void Blink(byte PIN, byte DELAY_MS, byte loops)
{
  for (byte i=0; i<loops; i++)
  {
    digitalWrite(PIN,LOW);
    delay(DELAY_MS);
    digitalWrite(PIN,HIGH);
    delay(DELAY_MS);
  }
}






1 Like

I was planning on using the Photon’s because the code I’m running requires a 32 Bit processor to run some complicated math for a sun tracking project.

The Photon is cheap and having WiFi built in is a free bonus over buying a similarly priced processor like the Teensy 3.2. You can always take manual control over the WiFi using the System Modes functions that Peekay pointed out.

I was not planning on using the Mesh networking but do plan on testing that out in the future.

I’ve actually decided on just going with the Photons on this project since I can accomplish all my goals using WiFi and the SOFT AP Setup Photon hosted Web Page application. Still learning how to get this setup to meet my needs though.

All that being said I’m still interested in figuring out how to get data received from on RFM95 / Photon combo onto another RFM95 / Photon combo so I can save that incoming data to a variable so I can then send it off to the web to a dashboard.

I posted a question on the LowPowerLab’s forum where a guy is using the Core and RFM69 radios to send sensor data from other RFM69 radios collecting data around his house. I need to see if he replied back.

Looking forward to your GPS code so hopefully I can learn something from it :wink:

@RWB Glad you eventually came right. I’m running into the same issue as you did - the reliable datagram example only yields limited range (1-2 rooms), whereas, the driver only example yields at least 3x the range (for me about 100 feet).

I’m using 2 Photons connected to CC110L radios (Anaren module, 915 MHz). So it uses the CC110 driver instead of the RF95 you’re using. But I’m curious as to how you eventually solved it? (Reading the entire post and it is not clear if @luisgcu made a modification to the driver that solved it).

Supposedly the manager and the driver both have the same default initialization (e.g. 5 dBm transmit power, etc.) so I’m struggling why the two sketches would yield such a difference.

@luisgcu your screenshots of the desktop IDE setup has been invaluable!

@bloukingfisher

I had to change the modem config settings to get the reliable datagram radio head example to work at longer ranges.

The Modem Config lines are in one of the .H or .CPP files for the RFM95w folders, you'll have to search for them but the first one he recommends will get you going with the RFM95w radios at least.

hi @bloukingfisher did you tried the example included on RadioHead library?
settings for that radio are no the same as RFM95 /96, the radio you use is FSK modulation.

// cc110_client.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple messageing client
// with the RH_CC110 class. RH_CC110 class does not provide for addressing or
// reliability, so you should only use RH_CC110 if you do not need the higher
// level messaging abilities.
// It is designed to work with the other example cc110_server
// Tested with Teensy 3.1 and Anaren 430BOOST-CC110L

#include <SPI.h>
#include <RH_CC110.h>

// Singleton instance of the radio driver
RH_CC110 cc110;

void setup() 
{
  Serial.begin(9600);
  while (!Serial)
    ; // wait for serial port to connect. Needed for native USB

  // CC110L may be equipped with either 26 or 27MHz crystals. You MUST
  // tell the driver if a 27MHz crystal is installed for the correct configuration to
  // occur. Failure to correctly set this flag will cause incorrect frequency and modulation
  // characteristics to be used. You can call this function, or pass it to the constructor
  cc110.setIs27MHz(true); // Anaren 430BOOST-CC110L Air BoosterPack test boards have 27MHz
  if (!cc110.init())
    Serial.println("init failed");
  // After init(), the following default values apply:
  // TxPower: TransmitPower5dBm
  // Frequency: 915.0
  // Modulation: GFSK_Rb1_2Fd5_2 (GFSK, Data Rate: 1.2kBaud, Dev: 5.2kHz, RX BW 58kHz, optimised for sensitivity)
  // Sync Words: 0xd3, 0x91
  // But you can change them:
//  cc110.setTxPower(RH_CC110::TransmitPowerM30dBm);
//  cc110.setModemConfig(RH_CC110::GFSK_Rb250Fd127);
//cc110.setFrequency(928.0);
}

void loop()
{
  Serial.println("Sending to cc110_server");
  // Send a message to cc110_server
  uint8_t data[] = "Hello World!";
  cc110.send(data, sizeof(data));
  
  cc110.waitPacketSent();
  // Now wait for a reply
  uint8_t buf[RH_CC110_MAX_MESSAGE_LEN];
  uint8_t len = sizeof(buf);

  if (cc110.waitAvailableTimeout(3000))
  { 
    // Should be a reply message for us now   
    if (cc110.recv(buf, &len))
   {
      Serial.print("got reply: ");
      Serial.println((char*)buf);
//      Serial.print("RSSI: ");
//      Serial.println(cc110.lastRssi(), DEC);    
    }
    else
    {
      Serial.println("recv failed");
    }
  }
  else
  {
    Serial.println("No reply, is cc110_server running?");
  }

  delay(400);
}

Thanks @luisgcu, yes when I’m using the CC110 DRIVER example from the example directory, like you listed, it works reasonably well (about 100 feet through brick/drywall - although nothing quite like the promised 194-260 yards from Anaren’s line of sight range test).

The examples do not include a reliable datagram for CC110, but looking at the documentation and inheritances there should be no reason that the reliable datagram manager and driver for CC110 can’t work. And in fact they do, except the range drops to 1-2 rooms (say < 40 feet). Here is the RF95 datagram example server code I modified for using with the CC110 driver (same for client code). Only changes are calling the CC110 driver essentially. I did try setting the power at max of 10 dBm but it didn’t make a noticeable change.

So I’m at a loss why the driver example on its own achieves a better range than the reliable datagram manager code. I could possibly skip using the manager, but I do like the benefits of the acknowledgements, etc that comes with the manager.

 // rf95_reliable_datagram_server.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple addressed, reliable messaging server
// with the RHReliableDatagram class, using the RH_RF95 driver to control a RF95 radio.
// It is designed to work with the other example rf95_reliable_datagram_client
// Tested with Anarduino MiniWirelessLoRa, Rocket Scream Mini Ultra Pro with the RFM95W

#include <RHReliableDatagram.h>
#include <RH_CC110.h>
//#include <RH_RF95.h>
//#include <SPI.h>

#define CLIENT_ADDRESS 1
#define SERVER_ADDRESS 2

// Singleton instance of the radio driver
RH_CC110 driver;
//RH_CC110 cc110;
//RH_RF95 driver;
//RH_RF95 driver(5, 2); // Rocket Scream Mini Ultra Pro with the RFM95W

// Class to manage message delivery and receipt, using the driver declared above
RHReliableDatagram manager(driver, SERVER_ADDRESS);

// Need this on Arduino Zero with SerialUSB port (eg RocketScream Mini Ultra Pro)
//#define Serial SerialUSB

void setup()
{
  // Rocket Scream Mini Ultra Pro with the RFM95W only:
  // Ensure serial flash is not interfering with radio communication on SPI bus
//  pinMode(4, OUTPUT);
//  digitalWrite(4, HIGH);

  Serial.begin(9600);
  //while (!Serial) ; // Wait for serial port to be available
delay(2000);


  if (!manager.init())
    Serial.println("init failed");
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on



// CC110L may be equipped with either 26 or 27MHz crystals. You MUST
// tell the driver if a 27MHz crystal is installed for the correct configuration to
// occur. Failure to correctly set this flag will cause incorrect frequency and modulation
// characteristics to be used. You can call this function, or pass it to the constructor
driver.setIs27MHz(true); // Anaren 430BOOST-CC110L Air BoosterPack test boards have 27MHz
if (!driver.init())
  Serial.println("init failed");
// After init(), the following default values apply:
// TxPower: TransmitPower5dBm
// Frequency: 915.0
// Modulation: GFSK_Rb1_2Fd5_2 (GFSK, Data Rate: 1.2kBaud, Dev: 5.2kHz, RX BW 58kHz, optimised for sensitivity)
// Sync Words: 0xd3, 0x91
// But you can change them:
//  cc110.setTxPower(RH_CC110::TransmitPowerM30dBm);
//driver.setTxPower(RH_CC110::TransmitPowerM30dBm);
driver.setTxPower(RH_CC110::TransmitPower10dBm);
//driver.setTxPower(RH_CC110::TransmitPowerM15dBm);
//  cc110.setModemConfig(RH_CC110::GFSK_Rb250Fd127);
//cc110.setFrequency(928.0);

/*
TransmitPowerM30dBm 	=-30dBm
TransmitPowerM20dBm 	=-20dBm
TransmitPowerM15dBm 	=-15dBm
TransmitPowerM10dBm 	=-10dBm
TransmitPower0dBm 	=0dBm
TransmitPower5dBm 	=5dBm
TransmitPower7dBm 	=7dBm
TransmitPower10dBm 	=10dBm
*/
}

uint8_t data[] = "And hello back to you";
// Dont put this on the stack:
uint8_t buf[RH_CC110_MAX_MESSAGE_LEN];

void loop()
{
  if (manager.available())
  {
    // Wait for a message addressed to us from the client
    uint8_t len = sizeof(buf);
    uint8_t from;
    if (manager.recvfromAck(buf, &len, &from))
    {
      Serial.print("got request from : 0x");
      Serial.print(from, HEX);
      Serial.print(": ");
      Serial.println((char*)buf);

      // Send a reply back to the originator client
      if (!manager.sendtoWait(data, sizeof(data), from))
        Serial.println("sendtoWait failed");
    }
  }
}

Came across a new optimized Arduino RFM95, RFM96, and RFM98 radios today and wanted to post it here. I have not tried this but look forward to doing that, it should be easy to get working on the Photon/Electron.

Here is another library built off the above library for Sparkfun RFM95 boards that have a pairing button process.

Hi, Rayan.
Did You try in Your Network all Clients to power from batteries?
If yes How You desided problem wake up of remote cliens?

I switched over to XBee 900 HP radios and they are running off a single 18650 cell in a application that never sleeps.

1 Like