My Raspberry Pi-based radiosonde receiver—affectionately and unimaginatively named PiSonde01P—has spent the last few years monitoring the 400 MHz radiosonde band and forwarding weather-balloon telemetry to SondeHub.
With an amateur-radio balloon launch planned for an upcoming JOTA-JOTI event, I wanted the station to do something more: continuously monitor the North American APRS frequency of 144.390 MHz and report amateur high-altitude balloon packets to APRS-IS and the SondeHub Amateur tracker.
The result is a dual-purpose Raspberry Pi receiver using two independently assigned RTL-SDRs:
SDR00002 → radiosonde_auto_rx → SondeHub
SDR00003 → rtl_fm → Dire Wolf → APRS-IS → SondeHub Amateur
One Pi, two SDRs, two balloon-tracking networks—and, eventually, one simulated balloon that “climbed” to 6,000 feet without ever leaving the ground.
The Existing PiSonde
The original station runs radiosonde_auto_rx, an open-source application developed by Project Horus. It scans the radiosonde band, detects compatible weather sondes, decodes their telemetry, and uploads the results to SondeHub.
That service continues to use the RTL-SDR identified as:
SDR00002
The important part is the serial number. With multiple identical USB receivers connected, relying on Linux device numbers such as device 0 or device 1 is asking for trouble. Those assignments can change during a reboot.
Giving each receiver a unique serial number lets every application request the correct hardware directly.
Adding the APRS Receiver
The second RTL-SDR, identified as SDR00003, is dedicated to 144.390 MHz. Its receive chain is straightforward:
rtl_fmtunes and demodulates the APRS frequency.- The resulting audio is piped into Dire Wolf.
- Dire Wolf decodes the 1200-baud AX.25/APRS packets.
- Qualifying packets are forwarded to APRS-IS using my verified amateur-radio callsign.
- The Project Horus APRS gateway identifies qualifying amateur-balloon packets and imports them into SondeHub Amateur.
The new station identifies as:
KN4OLA-2
It is configured as a receive-only iGate. It does not digipeat packets and does not gate Internet traffic back onto the radio channel.
The Project Horus documentation makes an important distinction: the SondeHub APRS gateway does not directly receive radio traffic or operate as an iGate. It monitors APRS-IS and imports qualifying balloon data and receiver information into SondeHub. A local application such as Dire Wolf is still required to receive and gate the radio packets.
More information is available from the SondeHub APRS Gateway project and the SondeHub Amateur Tracker project.
Advertising the Receiver’s Location
SondeHub needs to know the location of the station that received a balloon packet before it can plot that station on the map.
I added a Dire Wolf position beacon for KN4OLA-2:
PBEACON sendto=IG delay=0:30 every=30:00 symbol="igate" overlay=R lat=<LATITUDE>N long=<LONGITUDE>W comment="RX-only APRS iGate 144.390 MHz"
The most important setting is:
sendto=IG
That sends the position report directly to APRS-IS. It does not transmit the beacon over 144.390 MHz and therefore consumes no RF airtime.
The R overlay identifies the station as a receive-only iGate.
Once Dire Wolf restarted, the log showed that the station had connected and authenticated:
Now connected to IGate server noam.aprs2.net
# logresp KN4OLA-2 verified
A few seconds later, its position beacon appeared:
KN4OLA-2>APDW17:!3800.13NR07754.47W&
RX-only APRS iGate 144.390 MHz
APRS.fi confirmed that KN4OLA-2 was online and correctly positioned.
Simulating the Balloon
Before purchasing and assembling the actual balloon payload, I needed to prove the entire receive and reporting path.
I created a 1200-baud Bell 202 APRS audio file representing a simulated balloon using the callsign:
KN4OLA-12
The first test used a fixed ground-test location and reported an altitude of 400 feet:
KN4OLA-12>APZB01:!3759.63N/07757.65WO/A=000400 GROUND TEST - DO NOT CHASE
The balloon symbol and standard APRS altitude field were important because the SondeHub APRS gateway filters incoming traffic. A qualifying position must:
- Be an APRS position report
- Use the primary-table balloon symbol
- Include altitude using a standard APRS altitude format
- Avoid blocked paths, destination identifiers, and comment strings
I played the audio through a SignaLink connected to a radio on 144.390 MHz. Dire Wolf immediately decoded it:
KN4OLA-12 audio level = 66
KN4OLA-12>APZB01:!3759.63N/07757.65WO/A=000400
GROUND TEST - DO NOT CHASE
Within minutes, KN4OLA-12 appeared on SondeHub Amateur.
The Missing Receiver
The simulated balloon appeared on SondeHub, but KN4OLA-2 did not initially appear as one of the reporting stations.
The iGate was functioning. Dire Wolf had decoded the packet, APRS-IS had accepted it, and SondeHub displayed the balloon. The receiver marker was still missing.
The first issue was timing. The initial balloon packets reached APRS-IS before KN4OLA-2 had advertised its corrected position. I transmitted another ground-test packet after the receiver beacon was active, but the receiver marker still did not appear.
The reason was buried in the SondeHub APRS gateway logic: an APRS reporting station is uploaded as a receiver only after it receives a balloon packet above 1,500 meters—approximately 4,921 feet.
The 400-foot ground test could place the simulated payload on the Amateur tracker, but it could not activate the reporting-station marker. The threshold prevents vehicles and other low-altitude APRS users employing balloon symbols from filling the receiver layer with irrelevant stations.
That meant I needed one more controlled test.
The 6,000-Foot “Flight”
I created a separate APRS test packet reporting an altitude of 6,000 feet:
KN4OLA-12>APZB01:!3759.63N/07757.65WO/A=006000 RECEIVER TEST - DO NOT CHASE
The packet was transmitted once—not looped—and was clearly labeled as a receiver test.
Dire Wolf decoded the complete packet:
KN4OLA-12 audio level = 66
KN4OLA-12>APZB01:!3759.63N/07757.65WO/A=006000
RECEIVER TEST - DO NOT CHASE
Position, Original Balloon
N 37 59.6300, W 077 57.6500
alt 1829 m (6000 ft)
The packet exceeded SondeHub’s 1,500-meter threshold. A few minutes later, SondeHub Amateur displayed KN4OLA-2 as a reporting station approximately three miles from the simulated balloon.
Success.
Another local APRS station also received the test transmission, proving that even a brief ground test can travel farther than expected. That reinforced the decision to transmit only once and include the unmistakable RECEIVER TEST - DO NOT CHASE comment.
Testing Reboot Persistence
A working system is nice. A working system that survives a reboot is considerably more useful.
Before transmitting the final activation packet, I confirmed that both services were enabled and active:
auto_rx.service: enabled and active
aprs-igate.service: enabled and active
I then rebooted the Raspberry Pi and checked the entire system again.
The results were exactly what I wanted:
radiosonde_auto_rxreclaimedSDR00002- The APRS iGate reclaimed
SDR00003 - Both systemd services started automatically
- No systemd units failed
- Dire Wolf reconnected to APRS-IS
KN4OLA-2authenticated as a verified station- The Internet-only receiver beacon resumed
- The radiosonde scanner resumed searching the 400 MHz band
- SondeHub station uploads recovered automatically
Immediately after boot, radiosonde_auto_rx logged a few temporary DNS failures while the network was still initializing. Less than a minute later, it successfully uploaded its station information to SondeHub. The errors were transient and required no intervention.
Final Configuration
The completed PiSonde now supports two separate receiving missions:
Raspberry Pi 5
├── SDR00002
│ └── 400 MHz radiosonde reception
│ └── radiosonde_auto_rx
│ └── SondeHub
│
└── SDR00003
└── 144.390 MHz APRS reception
└── rtl_fm
└── Dire Wolf
└── APRS-IS
└── SondeHub Amateur
The associated amateur-radio identities are:
KN4OLA-2— Receive-only APRS iGateKN4OLA-10— Winlink VARA FM gatewayKN4OLA-12— Balloon payload and testing identity
The Ball Family Radio Operations Center is apparently becoming a very small telecommunications company.
Lessons Learned
Several details made the difference between “mostly working” and a properly commissioned station:
- Assign unique serial numbers to every RTL-SDR.
- Reference the receivers by serial number instead of their temporary USB device order.
- Advertise the iGate position directly to APRS-IS with
sendto=IG. - Use the
Roverlay to identify a receive-only iGate. - Ensure an amateur-balloon packet uses the proper APRS balloon symbol and standard altitude field.
- Remember that SondeHub’s receiver marker requires a qualifying balloon packet above 1,500 meters.
- Clearly identify every ground-test transmission and never leave test audio looping.
- Reboot the completed system and verify the complete signal path before declaring victory.
The station is now ready to support local amateur high-altitude balloon activity and our planned JOTA-JOTI launch. When the real payload takes flight, KN4OLA-2 will be waiting on 144.390 MHz to receive it.


