Repository navigation
PyTNC Pro v0.1.5-beta
PyTNC Pro v0.1.5-beta — Release Notes
Released: April 2026
TOCALL: APPR01
Python: 3.10–3.12 (3.12 recommended)
GitHub: https://github.com/smashingwaffle/pytnc-pro
Highlights
v0.1.5 is a deep protocol compliance release. Every area of the IGate implementation was audited against the authoritative APRS-IS specification and WB2OSZ's Understanding APRS Packets (February 2026 edition). The result is a substantially more correct IGate, a fixed third-party packet pipeline, and a cleaner live feed.
🌐 IGate — Full Protocol Compliance Audit
The IGate was audited line-by-line against:
- http://www.aprs-is.net/igating.aspx (APRS-IS IGate Design)
- http://www.aprs-is.net/IGateDetails.aspx (IGate Gating Criteria)
- WB2OSZ Understanding APRS Packets §2.6 Third Party header
Critical Fix — Third-Party Packet Unwrapping
This was a silent messaging bug. } (third-party) packets arriving on RF were classified as Other and discarded. This meant:
- Messages relayed from APRS-IS → TX IGate → RF were never processed
- No ACK was sent back to the sender
- The message never appeared in the message inbox
Third-party packets are now properly unwrapped: the } wrapper is stripped, the inner packet is re-parsed, and messages are delivered normally.
TX IGate Third-Party Format Fixed
The mandatory RF format is now spec-compliant:
IGATECALL>APRS,GATEPATH:}FROMCALL>TOCALL,TCPIP,IGATECALL*:data
Previously, APRS-IS path elements (qAR, qAC etc.) were leaking into the RF packet. The spec is explicit: q constructs must never appear on RF.
New TX IGate Gating Criteria
Two missing criteria from the spec were added:
- Criteria 2: Don't gate a message to RF if the sending station was recently heard on RF (they don't need internet delivery)
- Criteria 4: Don't gate a message to RF if the receiving station is internet-connected (
TCPIP*in path)
Other IGate Fixes
| Fix | Detail |
|---|---|
TCPXX added to all path checks |
Was only checking TCPIP |
Generic query ? packets blocked |
Per spec: must not gate to APRS-IS |
?IGATE? query now responded |
Replies with <IGATE,MSG_CNT=n,LOC_CNT=n capabilities |
| TX heard window default 30→60 min | Spec says 1 hour |
| TX IGate RF dedup | Same packet won't re-transmit to RF within 60s |
| APRS-IS login version string updated | Now sends PyTNC-Pro 0.1.5-beta |
📦 Packet Parser Improvements
New Packet Types
| Type | DTI | What changed |
|---|---|---|
| Killed object | ;NAME_ |
Now removes station from map via removeStation() |
| Item report | ) |
Now parsed — live ! and killed _ both handled |
Objects and items now try compressed position format first, with uncompressed as fallback.
Comment Cleaning
| Problem | Fix |
|---|---|
DAO !wpg! !wYa! showing in comments |
Was case-sensitive !W..!, now catches ![Ww].{2}! |
!x! matched any char |
Spec says literal lowercase x — fixed to .replace('!x!', '') |
RNG0001 70cm Voice D-Star... showing RNG prefix |
Strip RNG#### prefix used by D-Star/DMR/C4FM gateways |
Base91 |..| telemetry showing as garbage |
Strip pipe-delimited base91 blocks |
| Kenwood TM-D710 0xFF/0x00 bytes | Strip on decode before any parsing |
| Trailing CR/LF in RF packets | Strip before processing (IGate spec requirement) |
🗺️ Map & Display
Voice Frequency Tooltips
Station popups now display voice frequency, tone, and offset when present in the comment:
📻 145.450 MHz PL100 -600kHz
Parser now handles real-world variations:
145.450MHz(3 decimals, spec format)445.02500MHz +0.0000MHz(5 decimals, DMR gateway format)1288.450 -12MHz(no MHz suffix on offset)
Killed Objects/Items Removed from Map
When a killed object (_) or item (_) packet is received, the station marker, label, and trail are immediately removed from the map.
window.removeStation() Added
New JavaScript function in the map for programmatic station removal.
🐛 Bug Fixes
| Bug | Fix |
|---|---|
| Auto-beacon runaway — fired every second | Minimum 1-minute interval enforced |
| GPS re-centering map on every fix | Only centers on first fix |
| Hospitals always showing LA area | Cache now validates location; re-fetches if moved >35 miles |
| Hospital double-display on enable | Early return after cache load prevents fetch also running |
| Digipeater cache blocking UI | Converted from requests (blocking) to NetworkFetchWorker |
NetworkFetchWorker undefined in hospital fallback |
Added _mg() lookup inside _process_hospital_data |
| APRS-IS not-connected warning in wrong log | Now appears in APRS tab preset log |
| Binary garbage from APAT81 Anytone | Truncate at first run of 3+ garbage chars |
⚠️ IGate Beta Status
IGate (both RX and TX) is still considered beta. RX IGate has been tested live on KO6IKR-5 in Los Angeles. TX IGate has had significant correctness fixes this release but needs broader field testing.
If you run IGate and find unexpected behaviour, please open a GitHub issue with your IGate log output:
https://github.com/smashingwaffle/pytnc-pro/issues
📦 Build
Remove-Item PyTNC_Pro*.spec -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force build, dist -ErrorAction SilentlyContinue
pyinstaller --onedir --windowed --icon=pytnc_pro.ico --name "PyTNC_Pro_v0.1.5-beta" `
--add-data "aprs_symbols_48;aprs_symbols_48" `
--add-data "leaflet.js;." `
--add-data "leaflet.css;." `
--add-data "aprs_map.html;." `
--add-data "tnc;tnc" `
--add-data "pytnc_pro.ico;." `
main.pyReferences
- APRS-IS IGate Design
- APRS-IS IGate Details
- WB2OSZ Understanding APRS Packets — February 2026
- WB2OSZ aprsspec repository
73 de KO6IKR
always welcome to give me feedback
KO6IKR@Gmail.com