Farm LoRa Project: range testing

· 7 min read · Updated

On this page

Last time I got two radios talking on the bench. This time they had to talk across the farm.

the setup#

Both boards run the same firmware. The base sits at the house on the PC and logs everything. The mobile goes with me on a battery and pings the base every 2 seconds, and the base ACKs each one. The pings use the real farm packet format, not some throwaway test thing, so that got tested too.

sequenceDiagram
  participant M as Mobile (with me)
  participant B as Base (at the house)
  M->>B: ping every 2 s (asks for an ACK)
  B-->>M: ACK
  Note over M,B: base logs signal both ways, losses, marks
  B->>M: set TX power
  M-->>B: ACK, then both switch

The mobile's RGB LED goes green to yellow to red as the link gets worse. Pressing the BOOT button drops a numbered mark into the base's log so I can match lines to where I was standing. And the base can change the power on both radios over the air, so no walking back to the house to bump it up.

A line in the log looks like this:

range_walk_2026-09-27.logPlain text
11:02:32 *** MARK 7 ***
11:02:32 rx from 0x01 seq= 13  up  -86 dBm  down  -94 dBm  tx 10/10  lost 0  (total 36/321)

up is how strong the base heard the mobile, down is how strong the mobile heard the base, and tx is the power on each end.

day 1: the walk#

The goal wasn't max range. I want the lowest power that still covers the farm, so I started at 0 dBm (the lowest setting) and walked.

Basement, fine. The middle workshop, fine. The metal brooder barn, the building that kills the WiFi, fine. Bottom of the pasture, fine. 261 pings by that point and not one lost, all at 0 dBm. Into the woods, still solid. I was pretty surprised.

Pasture two, past the woods, is where it fell apart. 9 of the next 25 pings were lost. 36%, not something I'd trust with a fence alarm. So I bumped the power from the base and kept going.

power

where

lost

0 dBm

house down to the bottom of the pasture

0 of 261

0 dBm

pasture two

9 of 25 (36%)

5 dBm

pasture two

14 of 71 (20%)

10 dBm

furthest corner of the property

1 of 67 (1.5%)

10 dBm

the gate

0 of 18

5 dBm was still patchy. 10 dBm covered the far corner and the gate with basically nothing lost, so 10 dBm is the number. No need for full power (22 dBm) on the farm at all.

bugs I found on the walk#

The basement mark vanished. The mobile had restarted when I moved it onto the battery, which reset its mark counter, so the basement came in as mark 1 again and the base threw it out as a duplicate. The basement is lost to history.

Then every 8.5 minutes or so the base would yell "mobile restarted". It hadn't. The ping sequence number is 8 bits, so after 255 it wraps to 0, and the base took 0 as a reboot. Fixed in the code, but I didn't reflash mid walk so I just ignored it all morning.

And before I even left, the base's radio sometimes answered +++ with garbage. The firmware gave up without sending AT+RESET, so the radio sat in config mode deaf to everything. Now it resets and retries, up to 3 times.

RSSI is kind of useless out here#

In pasture two pings were getting lost, but the ones that made it still read around -94 dBm. The radio should hear down to about -120 at this speed, so that's supposedly 25 dB of headroom. Then going from 5 to 10 dBm didn't move the RSSI at all, when it should have read 5 dB stronger.

My guess is the module's RSSI reading flattens out around -95 to -105 and stops tracking weak signals, or the base next to the PC and a switching supply is seeing extra noise.

the first drive (did not go great)#

That afternoon I wanted to see how far it reaches off the farm at full power. Set both to 22 dBm, the uplink jumped about 23 dB like it should, and then the mobile restarted. Moved it to the car's USB, got about 40 seconds down the road, and it restarted again. Then the base's radio answered +++ with this:

range_walk_2026-09-27.logPlain text
13:58:49   +++ -> Power on

It only says that after it boots. So both radios were browning out at 22 dBm on jumper wire power (the mobile's 5 V was on a really thin one). Same problem as the bench bring-up, just louder. Called it for the day.

day 2: the base wasn't really powered#

Today the base was still acting broken, and not just at 22 dBm, at 17 and 10 too. The base heard the mobile fine but the mobile couldn't hear the base. The mobile's downlink reading sat at -91 on every ping (just a stale value) and it never got any power change commands.

Then I actually looked at the bench supply. Output on, 5.01 V, 0.000 A. Flat, for two minutes. The base radio wasn't drawing anything from it. Best guess is it was limping along on current leaking in through the data pin from the ESP32, enough to listen but not to transmit. Cycled the output, replugged the base, and it read 0.010 A like a normal idle radio. Everything worked after that.

So I'd spent a while debugging a radio that was barely plugged in.

I also figured out why +++ was so flaky: it fails if a ping from the mobile lands at the same moment. With the mobile off it worked on the first try.

the drive that worked#

First try at 22 dBm the mobile restarted 7 seconds in. Second try it held, and it held for the whole drive with no restarts.

Left the house at -64 both ways. The link lasted about 45 seconds of driving, fading as I went, and then:

range_test_2026-09-28.logPlain text
16:24:06 rx from 0x01 seq=109  up  -96 dBm  down -103 dBm  tx 22/22  lost 0  (total 2/118)
16:24:10 rx from 0x01 seq=111  up  -97 dBm  down  -98 dBm  tx 22/22  lost 1  (total 3/120)
16:24:20 --- no packets for 10 s ---
16:26:23 rx from 0x01 seq=176  up  -94 dBm  down -105 dBm  tx 22/22  lost 64  (total 67/185)
16:26:23 --- link back after 132 s ---

That last packet was about 1 km from the house in a straight line, right where the road goes downhill into lower ground and trees. Then about 2 minutes of nothing, 64 pings lost.

It came back at about 650 m on a higher stretch of road. Closer, sure, but my guess is that spot just has a more open view back across the valley. It dropped out twice more on the way back (30 s and 18 s), then got stronger until it was at -60 when I pulled in.

what the map showed#

Lining the drive up on a map with the log, distance mattered a lot less than what was in the way.

Last post I worked out the free-space path loss for the far well and said the range test would show how far off real life is. Here's the same math at 1 km:

FSPL=20log⁡10(1)+20log⁡10(915)+32.44≈91.7 dB\text{FSPL} = 20\log_{10}(1) + 20\log_{10}(915) + 32.44 \approx 91.7\ \text{dB}

So with nothing in the way, 22 dBm at 1 km should arrive around 22−91.7≈−70 dBm22 - 91.7 \approx -70\ \text{dBm}. I got about -97. Real life is roughly 27 dB worse, eaten by the house walls (the base is inside), the car, the hills and the trees.

The other thing is the Fresnel zone. With the base at desk height and the mobile on a dashboard, most of it is in the dirt and trees. Same story as pasture two.

What's the Fresnel zone?

A radio link doesn't just need the straight line between the antennas clear, it needs a fat oval of space around that line mostly clear too. The widest point is halfway, with a radius of about:

r=12λdr = \tfrac{1}{2}\sqrt{\lambda d}

At 915 MHz the wavelength λ\lambda is about 0.33 m, so over 1 km that's about 9 m out from the line. If a hill or a tree line pokes into that, you lose signal even when you can technically see the other end.

So the biggest win isn't more power, it's getting the base antenna outside and up high on the roof or a mast. And for the farm itself range isn't even the problem, 10 dBm covered the whole property with the base inside on a desk.

next#

Updated list from last time:

  • Get two radios talking on the bench

  • Range test around the farm (10 dBm covers all of it)

  • Get the base antenna outside and up high

  • Try the module's M0/M1 and AUX pins instead of shouting +++ and hoping no ping lands at the same time

  • BME280 node in the brooder barn

For real this time lol

$ echo "no bugs, just undocumented features"

© 2026 Anthony Kovach II