Long Range IoT Networks - Chapter 2 | Particle + LoRa Better together

Alright… in today’s adventures in LoRa, I learned you can only have ~2 (maybe 3) LoRa mesh nodes all within range of each other. As soon as I added the 3rd and especially the 4th LoRa mesh node (i.e. a node that services mesh messages by routing them), when I add a “end node” the route discovery message for it fails. I am pretty sure what’s going on is if 3 or more LoRa mesh nodes all hear the same mesh discovery message at the same time, then all 3+ will retransmit the route discovery message at nearly identical times and thus the message gets clobbered and nothing makes it through and the new node never self discovers a route.

Thankfully, in my use case, it’s not too big of a deal as 2 repeats (3 hops total) should easily cover the rural use case I’m after. I was tempted to enable CAD (channel activity detection) or possibly try adding a random delay when processing a LoRa mesh route discovery message to prevent the LoRa traffic from colliding but it seems things will get out of hand quick if say 10+ nodes all within range of each other wanted to service a route discovery message even with CAD and random delays. So avoiding that complexity for now.

So short of some new technique, it’s clear guidance for me to only have 2 LoRa Mesh repeaters per “LoRa network” or at least only have 2 that are within range of each other and no more. Currently I configure this using a DIP switch on the PCB anyhow.

As of now, I set it up to have 6 nodes total for more testing of robustness.
Node 1 <–> Gateway
Node 2 <–> Node 1 <–> gateway
Node 3 <–> Node 2 <–> Node 1 <–> Gateway
Node 4 <–> Node 2 <–> Node 1 <–> Gateway
Node 5 <–> Node 2 <–> Node 1 <–> Gateway
Node 6 <–> Node 2 <–> Node 1 <–> Gateway


I'd bet the Protocol contains some kind of measure to prevent this.
Large-Scale High-Density Networks is a core function for LoRa, I thought.
It's marketed for Smart Cities with 1,000's of devices.

I don't know what the answer is, but maybe stepping through the SF's, random delays, etc.
Or possibly a limitation w/ the Library that you're using ?

Unfortunately, the only thing that I have to offer is Encouragement :slight_smile:

1 Like

Yeah, to be a bit more clear… I fully expect to be able to accommodate 50-100+ LoRa nodes if it ever becomes necessary in a single deployment. It’s the fact that all 50 can not be configured to be a LoRa Mesh repeater. I’d plan to do more of a 1-2 nodes be configured as a mesh node and the remaining 48 are end nodes (i.e. do not attempt to re-route messages from neighboring nodes). They just send data (possibly through the 2 mesh repeaters) and then go back to sleep.

As for the smart cities with 1,000s of devices, yeah, that’s all LoRaWAN protocol which does not support mesh and therefore doesn’t do any type of “route discovery”. Nodes don’t have to repeat a broadcast it receives. I read a recent article that LoRaWAN is beginning to support repeaters but that’s a simple channel activity detection wake up and re-transmit whatever you heard and does not a “route”.

That said, I’m sure there are ways to provision it somehow to make many more nodes be a mesh, and this is likely a limitation of the current Radio Head library. I studied the RadioHead library in detail and already made several changes to it and I’m pretty sure there is no provision in it to account for this today. I know there are other sub Ghz mesh networks out there that must do route discovery, just not sure how they handle the route discovery component when many nodes try to re-broadcast at the same time. Maybe each repeater node has it’s own “re-broadcast” window so instead of re-broadcasting a route discovery right away, it waits for it’s specific turn to re-broadcast it. That would probably work… but it would be a significant development item.

Nearly all of my use cases won’t require more than 1-2 hops anyhow. It’s more about strategically locating 1 LoRa Mesh node at the highest spot on a property/hill to reach up/over a hill than trying to mesh many together and go miles. If someone is trying to cover miles, then I’d just put in another Particle + LoRa gateway on a different channel.

Thanks for the explanation..... that all makes sense.

True, My guess is that LoRa's built around it's Fair Use Policy, and that's a big factor.

For instance, with a XBee mesh you can routinely perform a "Find Neighbor" Command and receive replies back from dozens of nodes (used for Indoor Localization, like an indoor "GPS").
The big difference is this would be a Private Network with much higher bandwidth, verses LoRa that's much better for a "Community Wide" approach with it's Fair Use Policy.

I'll go ahead an appoligize for the dumb questions below:
In your deployment, I visualize several STAR networks that are centered around your Repeaters. The repeaters then provide the backhaul between each other to the final destination.
I assume your concern occurs in the Overlap of these STAR's footprint ( a new node being commissioned will be heard by too many repeaters, clogging up the channel) ?

Can you simply adjust the SF during the commissioning process to limit the range (if required) for the route discovery ?

So does each neighbor have an offset to when it sends a reply in XBee or does somehow XBee handle multiple devices on air at the same time for these replies? Maybe the higher bandwidth is such a short on air time that avoids conflicts. I believe a route discovery message is 70ms including the pre-amble for LoRa RadioHead library default radio settings.

Yeah basically, once the node discovers a route, it works nearly flawless from that point forward since it has a prescribed route for the message. Even of repeater nodes hear an application message as long as it's not participating in the route, it won't re-transmit it. It's only route discovery message that get hosed. Anytime multiple repeaters hear a route discovery message itself gets flooded and nothing gets through. Having many repeaters in a system is just fine, they just can all be within range of each other.

Per the RadioHead Library documentation:

When a RHMesh mesh node is initialised, it doe not know any routes to any other nodes (see RHRouter for details on route and the routing table). When you attempt to send a message with sendtoWait, will first check to see if there is a route to the destinastion node in the routing tabl;e. If not, it wil initialite 'Route Discovery'. When a node needs to discover a route to another node, it broadcasts MeshRouteDiscoveryMessage with a message type of RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST. Any node that receives such a request checks to see if it is a request for a route to itself (in which case it makes a unicast reply to the originating node with a MeshRouteDiscoveryMessage with a message type of RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE) otherwise it rebroadcasts the request, after adding itself to the list of nodes visited so far by the request.

It's the fact that all repeaters who heard the original message "rebroadcast" it at the same time that causes the issue. I may try to just add a short random delay to see if that helps at all.

Possibly... I am already using SF7 to keep the on air time low. I could reduce power during route discovery, but then it's artificially reducing range since the route discovery message won't travel as far.

Yeah, this is basically what I'm after. I think the 1-3 star networks covers most of the use cases I'm after as that should cover 100+ acres depending on terrain. Even if it's hilly, generally speaking you have the top of 1 hill to strategically locate a LoRa mesh node to service most of the area. The consequence in all of this is the customer/user will have to "pick" which node/s are repeaters, open the cover to flip a switch and then strategically locate that node. Was initially hoping all could be configured to be repeaters and the system would still "be happy" but that is not the case short of a lot more development.

1 Like

It’s been awhile since I posted here… It’s been a busy month or two building, shipping devices as well as making other necessary updates in my backend/web app to accommodate this LoRa Sensor node configuration. Happy to report that several systems are now coming “online” and fully installed/commissioned by a non-tech savvy end user. Several of these are also making 1 or more hops to get back to the Particle LoRa Gateway. The few that’s been installed and operating to date has been 2-3 weeks and the nodes haven’t missed a beat yet reporting either every 5 minutes or 20 minutes. Or if they missed a beat it was only 1 beat and fell back inline the next 5 minute interval.

I also was able to bench test 50 nodes all communicating to 1 Particle LoRa Gateway. This was more of an extreme use case and I thought of it more of a smoke test to see if this method is scalable to larger installations and so far so good. Should be an interesting few months for me as more and more systems come online.


Was randomly checking emails and opened one from Particle that caught my eye regarding Particle vs LoRaWAN. Was great to see Particle calling out out the Particle + LoRa combination and even better specifically referencing this thread in the article! Thought I’d post here in case others missed it. It’s a good read!



I have finally started to deploy my sleepy LoRA mesh in parks. More to come but these networks do seem to be stable and even weathered yesterday’s Cellular outage without loosing any data. My approach is similar to @jgskarda (he has been a great help to me in this project). My current focus is to provide coverage for nodes in remote parks where there is poor / no cellular coverage. As my installs will be low-density, I have limited (for now) the number of supported nodes to 10 per gateway.

I have tried to keep my code modular and as simple as possible. Key features:

  • Solar / Low-Power - all nodes and the gateway sleep
  • Single Particle function for all settings / status. Can configure a node in a single JSON payload
  • Gateway maintains a record of connection status / state / pending updates of the nodes

The GitHub repos are shared above as well as the hardware design for these devices.

These are my first two installs both of which have been working reliably for a week. Using these installs, my plan is to start to test different radio settings / antennas to see how far I can go with these devices without sacrificing reliability. I will share more as I get more experience.




Great work @Chip! Likewise great collaborating with you on this! It’s exciting to see these Particle + LoRa systems “come alive” and so far be quite stable. Will be great to hear more about the impact of range with antenna’s and Radio settings you are exploring!

I’ll eventually share more details of my overall go lives, lessens learned, opportunities, next steps, etc. Here is what just one of the many installs looks like. The Blue Circle in the top Left is a Particle Boron. The red dots everywhere else are LoRa nodes. This particular installation has been about 7 weeks now with all nodes sleeping/waking in sync. This also includes one of the nodes acting as a repeater/mesh router to get to the ML300 sensors in the far bottom right. So far it’s been working quite well!

Lots more fun to come!


@jgskarda ,

This looks fantastic with this many nodes over 7 weeks, you seem to have delivered a very reliable solution to your customers.

I will never have this many nodes in one area but I may need to relay messages to cover a large distance. Can you share what you needed to do to make one node a repeater? Does it stay awake for the full transmit window and does it need to be “listening”?

Thanks, Chip


Happy to share... in basic terms... the repeater LoRa Node wakes up at the same time as the Particle LoRa Gateway at the very start of the reporting window. It turns the radio on and then puts the MCU immediately back to sleep. The radio wakes the MCU up anytime it hears a transmission from any neighboring LoRa nodes using interrupts. The MCU then determines if the message needs to be transmitted and will either stay awake to re-transmit and if not, will just fall back asleep. This keeps the power slightly less on a repeater node than if it stayed fully awake the entire time. When it becomes it's turn to transmit, it will wake up itself, take readings and transmit it's own data. Then at the end of the reporting window when all nodes are done transmitting, the MCU wakes up just to turn the radio off and then the MCU sleeps. This is accomplished using interrupts from the radio OR an interrupt from the AB1805. Here was the visual that kind of illustrates it.


@jgskarda ,

I still have not worked up the nerve to try multithreading but I have a bigger energy budget than you do.

This makes perfect sense but it also make something clear to me, I need to either write the node software so the “repeater” function can be manually activated for a “node” or I need to have a separate role for “repeater”. It does not seem that a node would automatically discover that it was needed as a repeater for a more distant node. Is that true?

Also, I have been concerned about range so I thought I would do some testing to ease my mind:

First, I was worried that my carrier board layout may not have been correct as laying out antenna traces is a bit of a black art. I looked at a number of layouts and the only issue I could identify was that the u.fl footprint I got from SnapEDA did not follow the data sheet as it did not enforce a “keep out” under the connector which I had filled in with ground. I tested my carrier board against the Adafruit LoRA feather breakout with the same software and antenna and I saw much better performance with the carrier board. So, I believe my hardware design is OK. It is a bit hard to see as the u.fl connector is on the bottom (blue) side of the carrier board but I will implement a “keep out” area under the connector on the next rev.

Second, I went to a local park that was flat as I suspect that the terrain is my main issue in the Western NC parks. I was able to got 3/4 of a mile with RSSI at -126 and SNR at -3 coming through a fair bit of woods and a highway with concrete overpasses.

So, After this, I think I am confident in the hardware and software. Next up is to try some adjustments to the RadioHead Library defaults and to see if making adjustments in the frequency to match the center frequency of my particular antenna will make a difference. More to come.



That's great to hear @chipmc

I use a DIP switch on the PCB itself to indicate what mode is it in. I have a bank of 6 DIP switches for these types of static settings. When the node is powered on the first time, it looks at the status of the switch to say if it's a repeater node or end node along with what channel to use. I have a few spare switches too in case I need it in the future. Might be something to consider. I've thought about setting it via a LoRa message but figured it's a set it once and forget it.

In your case, you may consider just making them all repeaters. I avoided that due to larger power budget for repeater nodes with many nodes in a system but if you are talking 2-3 nodes I don't see any disadvantage. The RadioHead library will find a route either through the repeater or go direct. If your power budget on nodes can avoid it it may simplify things for you.

This is great! SNR is getting pretty low but RSSI seems like you could go a little farther yet. Maybe 1 mile?? Seems similar to the results I've been seeing.

This is a good next step. If I were you, I'd be most inclined to try the other modem configurations called out in the library. I tried some early testing of these. Bw31_25Cr48Sf512 was functional but in my early non-scientific tests it didn't show much of an improvement. I couldn't get the Bw125Cr48Sf4096 or Bw125Cr45Sf2048 talk at all. This was before I merged the RFM9X_RK library with the latest and greatest from RadioHead. Now that the libraries are synced again you may have better luck. Also, I didn't try too hard as for my use case of higher density nodes, I couldn't afford the longer on air time as it can be significant from ~70 ms to over 1 second from what I remember. More time broadcasting is more power used and less time for other nodes to talk. That said, if it doubles your range, maybe for your use case with a few nodes talking less frequent that would be well worth it.

Keep the observations and learnings coming! Great work!

    Bw125Cr45Sf128 	Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range.
    Bw500Cr45Sf128 	Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range.
    Bw31_25Cr48Sf512 Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range. - Functional - No noticable improvement
    Bw125Cr48Sf4096 Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, low data rate, CRC on. Slow+long range.
    Bw125Cr45Sf2048 Bw = 125 kHz, Cr = 4/5, Sf = 2048chips/symbol, CRC on. Slow+long range. - Not available in library

    if (!rf95.setModemConfig(RH_RF95::Bw125Cr45Sf128));

Experimenting with different profiles with a specific setup can lead to surprising results.

In some cases, a higher SF with double the transmission time, on top of longer range, can result in a significantly higher number of transmissions (longer battery life), because the peak current load profile on the battery is less severe.


So, I am trying to see what moves the needle on LoRA range. My metric is the RSSI and SNR values as reported by the gateway. As these values van vary from sample to sample, I tried to get at least a half-dozen readings and took an average.

My setup was to put the gateway at a distance and with enough obstacles to get to about -100 for RSSI this is not at the edge of the device’s limit but it is not so close that differences in readings would be overpowered by a strong signal. By putting the gateway about 1/4 mile away with two houses and some woods, I was able to get the reading I wanted. I put the gateway into “connected” mode where it maintained both a LoRA and a cellular connection to Particle. I assume this is less optimal than just having the LoRA radio on, but otherwise, I would need to walk to the Gateway each time I wanted to change a setting and life is too short for that.

Here is what I found that improved LoRA range:

  1. A decent omni-directional antenna. This made a significant - 20bB - change in the signal when I changed from a patch antenna to the rubber duck antenna that @jgskarda had already selected. I tried about 6 different patch and stick antennae and this was the best.


  1. Based on the data sheet from the antenna, it seems that the actual center frequency is not 915MHz but somewhere near 926MHz. Again, a tip of the hat to @jgskarda for pointing this out and supplying his value of 926.84MHz. Setting this as the center frequency for the LoRA radio gained another 3dB of signal strength.

  1. I looked at changing the values for the spreading factor and chips per byte and these only made modest changes in my testing. I may try this again when I am out in the woods as one of these setting may be better in environments with less ambient radio noise and mode trees / terrain.
Enumerator Timeout RSSI / SNR
Bw125Cr45Sf128 Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range. Default - 200mSec -90/9
Bw500Cr45Sf128 Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range. Default - 200mSec -91/5
Bw31_25Cr48Sf512 Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range. 2000 -91/5
Bw125Cr48Sf4096 Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, low data rate, CRC on. Slow+long range. 1000 -92/9
Bw125Cr45Sf2048 Bw = 125 kHz, Cr = 4/5, Sf = 2048chips/symbol, CRC on. Slow+long range. 2000 -96/9

None of these changes were enough to make me want to move off the default settings.

So, the net of this is - pick a good antenna, read its data sheet and go with the default software settings.

I put this into practice at the Umstead State Park and took the RSSI from -129 to -112. I will let this run over the next few weeks but, I believe this could make a significant difference in reliability.




Great information @chipmc Thanks for sharing!

Sounds like you were able to confirm my observations but in a much more scientific manner. This is great! I’m still surprised the SF not giving us more range. I wonder if the RSSI and SNR are not as indicative to total impact of potential range as we would think. What I mean by that is I wonder if the RSSI and SNR being nearly identical at say 1/4 mile does not actually prove anything and it’s not a true proxy of total range capability. From TTN: Spreading Factors | The Things Network

RSSI (received signal strength) would still be the same for all SFs since we are broadcasting since we always broadcast with the same power, we have the same losses and same signal attenuation so RSSI for all SFs would be the same at the same distance? I wonder if a better test would be to truly measure maximum range and not just RSSI and SNR at the same range.

I interpret this table as we can tolerate a lower RSSI with a SF12 vs SF7 and still receive the message successfully (i.e. we have more link budget) so just because we do not directionally see a change in RSSI at a fixed distance like you tested does not mean we won’t see improved range at a SF12.

I never tested total range capability at different SFs maybe that’s worth a repeat of your test?

1 Like

Yes, LoRa radio transmissions are not more powerful, but are more "powerfully received" even far beneath the noise floor on a frequency. A higher spreading factor (Sf) alone, is used for increasing range, or overcome more interference at the same range.

I would stay with 125Khz bandwith minimum, being safer across an outdoor temperature range with these radios.

Also note that the built-in CRC is somewhat far from perfect, so checking data validity is recommended, if this is not in the lib used.


@jgskarda ,

I see what you and @thrmttnw are getting at here. My approach was static range and looking for a different RSSI. Perhaps it needs to be dynamic range and simply looking for the point at which a connection is no longer possible.

There is a park nearby where I may have a chance to test this. The distances between the nodes will be quite large (up to two miles) but most of that distance will be crossing Lake Jordan. I am not sure if my current setup can cover this distance but thought it would be worth a shot. The only issue is that to make the logistics of this testing (which involves refreshing and resetting both node and gateway) require me to have cellular connection at both ends. This is not always easy as I am using LoRA specifically to compensate for low / no cellular coverage.

I like the idea of thinking about link budgets. I found Andreas Spiess’s introductory video helpful and he going on to talk about a number of different antennae.

One takeaway from this was when he was demonstrating a link budget calculator:

I definitely want to test the impact that elevation might have on the connection. The nodes need to be at ground level, and there is a cost associated with an antenna extension. But, the gateway can be elevated and I might give this a try as well.

I will let you know what I learn - until the community says “enough already”.



From my spot in the community I say 'keep going I am enjoying this adventure a lot'
Way to go guys!


@chipmc, in my experience a little Elevation and a Yagi goes a Long Way (pun intended) :grinning: