I would like to request an optional dynamic APRS-IS filtering feature for LoRa_APRS_iGate.
The goal is to better support high-altitude LoRa APRS stations, especially balloons, without requiring operators to use very large static APRS-IS radius filters such as m/300 or m/500.
Proposed behavior
Keep the operator's normal static APRS-IS filter, for example:
m/50
When the iGate hears a selected LoRa station over RF, dynamically add an APRS-IS friend-range filter around that station, for example:
m/50 f/SP0LND-6/20
Keep that dynamic filter active while the station remains in Last Heard
Automatically remove it when the station ages out
This would allow a LoRa iGate to follow APRS-IS traffic near a distant station that is actually within its RF coverage, without subscribing to all APRS traffic within a huge fixed radius around the iGate itself.
Use Case
This came up while tracking the Polish high-altitude balloon SP0LND-6 from my LoRa APRS iGate in Ridgecrest, California.
My iGate successfully received and gated SP0LND-6 from approximately 182 miles / 292 km away, while the balloon was at approximately 46,900 feet / 14,300 meters.
My station had LoRa TX enabled and APRS-IS-to-RF message/object support enabled.
However, my APRS-IS filter was:
m/50
or approximately 31 miles / 50 km.
That configuration made perfect sense from a traditional terrestrial APRS perspective, but the RF side of the LoRa iGate was hearing the balloon almost six times farther away than the APRS-IS radius I had configured.
The SP0LND-6 mission is specifically intended to support two-way communication with the balloon through third-party TX-capable LoRa APRS iGates.
That means a TX-capable iGate may be able to hear and transmit to a high-altitude balloon hundreds of kilometers away, while its APRS-IS filter is still configured only for normal local terrestrial traffic.
A large static radius such as:
m/300
would solve that problem in one sense, but it is not ideal. It causes the iGate to receive APRS traffic for a very large geographic area even when most of that traffic has no RF relevance.
A dynamic friend filter seems like a much cleaner solution.
Proposed Behavior
The operator would retain a normal base filter such as:
m/50
If the iGate hears:
SP0LND-6
over LoRa RF, the effective APRS-IS filter could become:
m/50 f/SP0LND-6/20
If it then also hears:
SP0LND-9
the effective filter could become:
m/50 f/SP0LND-6/20 f/SP0LND-9/20
When SP0LND-6 is no longer present in Last Heard, its friend filter would be removed:
m/50 f/SP0LND-9/20
When no dynamic stations remain, the filter returns to:
m/50
This preserves normal local APRS operation while temporarily following the actual RF neighborhood of distant LoRa stations.
Why Friend Filters Instead of a Large Static Radius?
A high-altitude LoRa station can have an enormous RF footprint.
In the SP0LND-6 mission documentation, LoRa links of approximately:
286 miles / 461 km
277 miles / 445 km
were demonstrated.
That means a terrestrial LoRa iGate can legitimately hear a balloon hundreds of kilometers away.
Using:
m/300
or:
m/500
for every iGate would pull in all APRS traffic within a huge area around the iGate, including many ground stations that are not realistically reachable over LoRa RF.
A dynamic friend filter follows only the station that the iGate has actually demonstrated it can hear.
That seems much more consistent with the normal amateur-radio goal of avoiding unnecessary traffic.
Suggested Configuration Options
It would be helpful to add a new configuration section in the Web UI, perhaps under APRS-IS:
( ) All recently heard LoRa stations
( ) Callsign prefix
( ) APRS symbol
( ) Prefix OR symbol
Callsign Prefixes
Example:
SP0LND
Potentially allow multiple prefixes, comma-separated or space-separated:
SP0LND, W5KUB, HAB
APRS Symbols
Allow operators to select one or more APRS symbols, especially:
Balloon
This could be useful for operators who want to automatically support any high-altitude balloon rather than only a particular project.
Friend Radius
Example default:
20 km
This would generate:
f/CALLSIGN/20
Timeout
Example:
15 minutes
A dynamic filter would remain active while the station is being heard and expire after the configured Last Heard timeout.
Maximum Dynamic Stations
A configurable or hard maximum would be useful to prevent the filter string from growing without bounds.
For example:
Maximum dynamic stations: 9
Integration with Existing Last Heard Logic
The firmware already maintains a Last Heard list for LoRa stations.
It also already uses that information to determine whether an APRS-IS message should be transmitted back to RF.
That existing behavior is important and should remain in place.
For example:
APRS-IS sends a message addressed to SP0LND-6
The iGate receives that message because SP0LND-6 is included in the effective APRS-IS filter
Before transmitting it over LoRa RF, the firmware still checks whether SP0LND-6 was recently heard locally
If it was not recently heard, the packet is not transmitted
In other words:
APRS-IS filtering determines what traffic the iGate receives from the Internet.
Last Heard still determines what the iGate is willing to transmit over RF.
That separation seems both efficient and safe.
Dynamic Filter Updates Without Reconnecting
If possible, it would be preferable to update the APRS-IS filter dynamically rather than disconnecting and reconnecting every time the Last Heard list changes.
The server-side filter could be updated with something like:
#filter m/50 f/SP0LND-6/20
This would allow dynamic stations to be added and removed without disrupting the APRS-IS session.
Local terrestrial stations continue to work normally within approximately 31 miles / 50 km.
A high-altitude balloon appears:
SP0LND-6
at 182 miles / 292 km.
The iGate hears it directly over LoRa RF.
Dynamic filter becomes:
m/50 f/SP0LND-6/20
The iGate can now receive APRS-IS traffic relevant to the balloon's current local area without subscribing to all APRS traffic within 186 miles / 300 km of the iGate.
When the balloon moves out of RF range and expires from Last Heard, the filter automatically returns to:
m/50
Why This Would Be Useful Beyond SP0LND
Although SP0LND-6 is what exposed this issue for me, the feature would be useful for:
High-altitude balloons
Pico balloons
Airborne LoRa APRS digipeaters
Aircraft trackers
Mountain-top portable stations
Long-distance tropospheric or line-of-sight LoRa experiments
Mobile stations temporarily heard far outside a normal local radius
The broader issue is that LoRa RF coverage is not always well represented by a fixed geographic radius around the iGate.
A station may be hundreds of kilometers away and still be a legitimate RF neighbor.
Optional Simpler Version
If a full dynamic friend-filter implementation is too large a change, a simpler intermediate feature could be:
Automatic Callsign-Prefix Filters
For example:
m/50 p/SP0LND
This would allow the operator to keep normal local traffic while always following all SP0LND stations.
That would already be useful for balloon support.
However, the dynamic friend-filter approach would be much more flexible and efficient because it would follow only stations the iGate is actually hearing.
Closing
I think this feature would make the iGate behave more intelligently for the kinds of long-distance RF paths that LoRa makes possible.
The issue I encountered was essentially:
RF coverage: ~182 miles / 292 km
APRS-IS filter: ~31 miles / 50 km
The radio could communicate with a station that the Internet-side configuration still considered far outside the local area.
A dynamic APRS-IS friend filter based on recently heard LoRa stations would bridge that gap without requiring every operator to configure an excessively large static radius.
Thanks for considering it.
73, Edward / KI6PSP
# Feature Request: Dynamic APRS-IS Friend Filters for Recently Heard LoRa Stations
## Summary
I would like to request an optional **dynamic APRS-IS filtering feature** for `LoRa_APRS_iGate`.
The goal is to better support **high-altitude LoRa APRS stations, especially balloons**, without requiring operators to use very large static APRS-IS radius filters such as `m/300` or `m/500`.
- ### Proposed behavior
Keep the operator's normal static APRS-IS filter, for example:
```text
m/50
```
When the iGate hears a selected LoRa station over RF, dynamically add an APRS-IS **friend-range filter** around that station, for example:
```text
m/50 f/SP0LND-6/20
```
Keep that dynamic filter active while the station remains in **Last Heard**
Automatically remove it when the station ages out
This would allow a LoRa iGate to follow APRS-IS traffic near a distant station that is actually within its RF coverage, without subscribing to all APRS traffic within a huge fixed radius around the iGate itself.
---
## Use Case
This came up while tracking the Polish high-altitude balloon **SP0LND-6** from my LoRa APRS iGate in Ridgecrest, California.
My iGate successfully received and gated SP0LND-6 from approximately **182 miles / 292 km away**, while the balloon was at approximately **46,900 feet / 14,300 meters**.
My station had LoRa TX enabled and APRS-IS-to-RF message/object support enabled.
However, my APRS-IS filter was:
```text
m/50
```
or approximately **31 miles / 50 km**.
That configuration made perfect sense from a traditional terrestrial APRS perspective, but the RF side of the LoRa iGate was hearing the balloon almost six times farther away than the APRS-IS radius I had configured.
The SP0LND-6 mission is specifically intended to support **two-way communication with the balloon through third-party TX-capable LoRa APRS iGates**.
That means a TX-capable iGate may be able to hear and transmit to a high-altitude balloon hundreds of kilometers away, while its APRS-IS filter is still configured only for normal local terrestrial traffic.
A large static radius such as:
```text
m/300
```
would solve that problem in one sense, but it is not ideal. It causes the iGate to receive APRS traffic for a very large geographic area even when most of that traffic has no RF relevance.
A dynamic friend filter seems like a much cleaner solution.
---
## Proposed Behavior
The operator would retain a normal base filter such as:
```text
m/50
```
If the iGate hears:
```text
SP0LND-6
```
over LoRa RF, the effective APRS-IS filter could become:
```text
m/50 f/SP0LND-6/20
```
If it then also hears:
```text
SP0LND-9
```
the effective filter could become:
```text
m/50 f/SP0LND-6/20 f/SP0LND-9/20
```
When `SP0LND-6` is no longer present in Last Heard, its friend filter would be removed:
```text
m/50 f/SP0LND-9/20
```
When no dynamic stations remain, the filter returns to:
```text
m/50
```
This preserves normal local APRS operation while temporarily following the actual RF neighborhood of distant LoRa stations.
---
## Why Friend Filters Instead of a Large Static Radius?
A high-altitude LoRa station can have an enormous RF footprint.
In the SP0LND-6 mission documentation, LoRa links of approximately:
- **286 miles / 461 km**
- **277 miles / 445 km**
were demonstrated.
That means a terrestrial LoRa iGate can legitimately hear a balloon hundreds of kilometers away.
Using:
```text
m/300
```
or:
```text
m/500
```
for every iGate would pull in all APRS traffic within a huge area around the iGate, including many ground stations that are not realistically reachable over LoRa RF.
A dynamic friend filter follows only the station that the iGate has actually demonstrated it can hear.
That seems much more consistent with the normal amateur-radio goal of avoiding unnecessary traffic.
---
## Suggested Configuration Options
It would be helpful to add a new configuration section in the Web UI, perhaps under APRS-IS:
```text
Dynamic APRS-IS Filtering
[ ] Enable dynamic filters for heard LoRa stations
```
### Match Mode
```text
( ) All recently heard LoRa stations
( ) Callsign prefix
( ) APRS symbol
( ) Prefix OR symbol
```
### Callsign Prefixes
Example:
```text
SP0LND
```
Potentially allow multiple prefixes, comma-separated or space-separated:
```text
SP0LND, W5KUB, HAB
```
### APRS Symbols
Allow operators to select one or more APRS symbols, especially:
- Balloon
This could be useful for operators who want to automatically support any high-altitude balloon rather than only a particular project.
### Friend Radius
Example default:
```text
20 km
```
This would generate:
```text
f/CALLSIGN/20
```
### Timeout
Example:
```text
15 minutes
```
A dynamic filter would remain active while the station is being heard and expire after the configured Last Heard timeout.
### Maximum Dynamic Stations
A configurable or hard maximum would be useful to prevent the filter string from growing without bounds.
For example:
```text
Maximum dynamic stations: 9
```
---
## Integration with Existing Last Heard Logic
The firmware already maintains a **Last Heard** list for LoRa stations.
It also already uses that information to determine whether an APRS-IS message should be transmitted back to RF.
That existing behavior is important and should remain in place.
For example:
1. APRS-IS sends a message addressed to `SP0LND-6`
2. The iGate receives that message because `SP0LND-6` is included in the effective APRS-IS filter
3. Before transmitting it over LoRa RF, the firmware still checks whether `SP0LND-6` was recently heard locally
4. If it was not recently heard, the packet is not transmitted
In other words:
> **APRS-IS filtering determines what traffic the iGate receives from the Internet.**
>
> **Last Heard still determines what the iGate is willing to transmit over RF.**
That separation seems both efficient and safe.
---
## Dynamic Filter Updates Without Reconnecting
If possible, it would be preferable to update the APRS-IS filter dynamically rather than disconnecting and reconnecting every time the Last Heard list changes.
The server-side filter could be updated with something like:
```text
#filter m/50 f/SP0LND-6/20
```
This would allow dynamic stations to be added and removed without disrupting the APRS-IS session.
A possible internal structure might be:
```cpp
String buildEffectiveAprsIsFilter();
void updateAprsIsDynamicFilter();
```
Where:
```text
effective filter =
base configured filter
+
active dynamic friend filters
```
The configured base filter should remain unchanged in persistent settings.
---
## Suggested Matching Logic
Pseudo-logic:
```cpp
onLoRaPacketReceived(packet) {
updateLastHeard(packet.sender);
if (!dynamicFilterEnabled)
return;
if (!packetHasValidPosition(packet))
return;
if (matchesConfiguredPrefix(packet.sender) ||
matchesConfiguredSymbol(packet.symbol) ||
dynamicMode == ALL_HEARD) {
addOrRefreshDynamicStation(packet.sender);
updateAprsIsDynamicFilter();
}
}
```
Periodic cleanup:
```cpp
for each dynamic station {
if (stationIsExpiredFromLastHeard(station)) {
removeDynamicStation(station);
filterChanged = true;
}
}
if (filterChanged) {
updateAprsIsDynamicFilter();
}
```
---
## Example Scenario
Base filter:
```text
m/50
```
Local terrestrial stations continue to work normally within approximately **31 miles / 50 km**.
A high-altitude balloon appears:
```text
SP0LND-6
```
at **182 miles / 292 km**.
The iGate hears it directly over LoRa RF.
Dynamic filter becomes:
```text
m/50 f/SP0LND-6/20
```
The iGate can now receive APRS-IS traffic relevant to the balloon's current local area without subscribing to all APRS traffic within **186 miles / 300 km** of the iGate.
When the balloon moves out of RF range and expires from Last Heard, the filter automatically returns to:
```text
m/50
```
---
## Why This Would Be Useful Beyond SP0LND
Although SP0LND-6 is what exposed this issue for me, the feature would be useful for:
- High-altitude balloons
- Pico balloons
- Airborne LoRa APRS digipeaters
- Aircraft trackers
- Mountain-top portable stations
- Long-distance tropospheric or line-of-sight LoRa experiments
- Mobile stations temporarily heard far outside a normal local radius
The broader issue is that **LoRa RF coverage is not always well represented by a fixed geographic radius around the iGate**.
A station may be hundreds of kilometers away and still be a legitimate RF neighbor.
---
## Optional Simpler Version
If a full dynamic friend-filter implementation is too large a change, a simpler intermediate feature could be:
### Automatic Callsign-Prefix Filters
For example:
```text
m/50 p/SP0LND
```
This would allow the operator to keep normal local traffic while always following all SP0LND stations.
That would already be useful for balloon support.
However, the dynamic friend-filter approach would be much more flexible and efficient because it would follow only stations the iGate is actually hearing.
---
## Closing
I think this feature would make the iGate behave more intelligently for the kinds of long-distance RF paths that LoRa makes possible.
The issue I encountered was essentially:
```text
RF coverage: ~182 miles / 292 km
APRS-IS filter: ~31 miles / 50 km
```
The radio could communicate with a station that the Internet-side configuration still considered far outside the local area.
A dynamic APRS-IS friend filter based on recently heard LoRa stations would bridge that gap without requiring every operator to configure an excessively large static radius.
Thanks for considering it.
73,
**Edward / KI6PSP**
<!-- github-sync-id:5376993677 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Feature Request: Dynamic APRS-IS Friend Filters for Recently Heard LoRa Stations
Summary
I would like to request an optional dynamic APRS-IS filtering feature for
LoRa_APRS_iGate.The goal is to better support high-altitude LoRa APRS stations, especially balloons, without requiring operators to use very large static APRS-IS radius filters such as
m/300orm/500.Proposed behavior
Keep the operator's normal static APRS-IS filter, for example:
When the iGate hears a selected LoRa station over RF, dynamically add an APRS-IS friend-range filter around that station, for example:
Keep that dynamic filter active while the station remains in Last Heard
Automatically remove it when the station ages out
This would allow a LoRa iGate to follow APRS-IS traffic near a distant station that is actually within its RF coverage, without subscribing to all APRS traffic within a huge fixed radius around the iGate itself.
Use Case
This came up while tracking the Polish high-altitude balloon SP0LND-6 from my LoRa APRS iGate in Ridgecrest, California.
My iGate successfully received and gated SP0LND-6 from approximately 182 miles / 292 km away, while the balloon was at approximately 46,900 feet / 14,300 meters.
My station had LoRa TX enabled and APRS-IS-to-RF message/object support enabled.
However, my APRS-IS filter was:
or approximately 31 miles / 50 km.
That configuration made perfect sense from a traditional terrestrial APRS perspective, but the RF side of the LoRa iGate was hearing the balloon almost six times farther away than the APRS-IS radius I had configured.
The SP0LND-6 mission is specifically intended to support two-way communication with the balloon through third-party TX-capable LoRa APRS iGates.
That means a TX-capable iGate may be able to hear and transmit to a high-altitude balloon hundreds of kilometers away, while its APRS-IS filter is still configured only for normal local terrestrial traffic.
A large static radius such as:
would solve that problem in one sense, but it is not ideal. It causes the iGate to receive APRS traffic for a very large geographic area even when most of that traffic has no RF relevance.
A dynamic friend filter seems like a much cleaner solution.
Proposed Behavior
The operator would retain a normal base filter such as:
If the iGate hears:
over LoRa RF, the effective APRS-IS filter could become:
If it then also hears:
the effective filter could become:
When
SP0LND-6is no longer present in Last Heard, its friend filter would be removed:When no dynamic stations remain, the filter returns to:
This preserves normal local APRS operation while temporarily following the actual RF neighborhood of distant LoRa stations.
Why Friend Filters Instead of a Large Static Radius?
A high-altitude LoRa station can have an enormous RF footprint.
In the SP0LND-6 mission documentation, LoRa links of approximately:
were demonstrated.
That means a terrestrial LoRa iGate can legitimately hear a balloon hundreds of kilometers away.
Using:
or:
for every iGate would pull in all APRS traffic within a huge area around the iGate, including many ground stations that are not realistically reachable over LoRa RF.
A dynamic friend filter follows only the station that the iGate has actually demonstrated it can hear.
That seems much more consistent with the normal amateur-radio goal of avoiding unnecessary traffic.
Suggested Configuration Options
It would be helpful to add a new configuration section in the Web UI, perhaps under APRS-IS:
Match Mode
Callsign Prefixes
Example:
Potentially allow multiple prefixes, comma-separated or space-separated:
APRS Symbols
Allow operators to select one or more APRS symbols, especially:
This could be useful for operators who want to automatically support any high-altitude balloon rather than only a particular project.
Friend Radius
Example default:
This would generate:
Timeout
Example:
A dynamic filter would remain active while the station is being heard and expire after the configured Last Heard timeout.
Maximum Dynamic Stations
A configurable or hard maximum would be useful to prevent the filter string from growing without bounds.
For example:
Integration with Existing Last Heard Logic
The firmware already maintains a Last Heard list for LoRa stations.
It also already uses that information to determine whether an APRS-IS message should be transmitted back to RF.
That existing behavior is important and should remain in place.
For example:
SP0LND-6SP0LND-6is included in the effective APRS-IS filterSP0LND-6was recently heard locallyIn other words:
That separation seems both efficient and safe.
Dynamic Filter Updates Without Reconnecting
If possible, it would be preferable to update the APRS-IS filter dynamically rather than disconnecting and reconnecting every time the Last Heard list changes.
The server-side filter could be updated with something like:
This would allow dynamic stations to be added and removed without disrupting the APRS-IS session.
A possible internal structure might be:
Where:
The configured base filter should remain unchanged in persistent settings.
Suggested Matching Logic
Pseudo-logic:
Periodic cleanup:
Example Scenario
Base filter:
Local terrestrial stations continue to work normally within approximately 31 miles / 50 km.
A high-altitude balloon appears:
at 182 miles / 292 km.
The iGate hears it directly over LoRa RF.
Dynamic filter becomes:
The iGate can now receive APRS-IS traffic relevant to the balloon's current local area without subscribing to all APRS traffic within 186 miles / 300 km of the iGate.
When the balloon moves out of RF range and expires from Last Heard, the filter automatically returns to:
Why This Would Be Useful Beyond SP0LND
Although SP0LND-6 is what exposed this issue for me, the feature would be useful for:
The broader issue is that LoRa RF coverage is not always well represented by a fixed geographic radius around the iGate.
A station may be hundreds of kilometers away and still be a legitimate RF neighbor.
Optional Simpler Version
If a full dynamic friend-filter implementation is too large a change, a simpler intermediate feature could be:
Automatic Callsign-Prefix Filters
For example:
This would allow the operator to keep normal local traffic while always following all SP0LND stations.
That would already be useful for balloon support.
However, the dynamic friend-filter approach would be much more flexible and efficient because it would follow only stations the iGate is actually hearing.
Closing
I think this feature would make the iGate behave more intelligently for the kinds of long-distance RF paths that LoRa makes possible.
The issue I encountered was essentially:
The radio could communicate with a station that the Internet-side configuration still considered far outside the local area.
A dynamic APRS-IS friend filter based on recently heard LoRa stations would bridge that gap without requiring every operator to configure an excessively large static radius.
Thanks for considering it.
73,
Edward / KI6PSP