Adding Custom Fields to an ADIF File

I’m not much of a programmer. I’ll be the first to admit that. But, now and then, I manage to cobble together a useful script using the Python programming language to make short work of repetitive, tedious tasks. Here’s an example.

I described my process for logging contacts in a previous post. Part of that process is keeping track of where I was at the time and what rig I was using. My main log in N3FJP’s ACLog uses the other fields feature to implement the ADIF tags, MY_QTH and MY_RIG. Adding that information to ADIF files being imported into my main logging program was time-consuming.

I had been using ADIF Master to add these fields and populate them. I still highly recommend ADIF Master but I wanted to see if I could automate things using Python.

What I ended up with is a script that prompts me to enter my location and rig. If the ADIF file doesn’t already include a tag for TX_PWR, the script prompts me to enter my transmit power also. It then generates these new tags and inserts them in each record in the file. It takes me about 15 seconds to execute the script.

As I noted earlier, I’m no programmer. So, this code might not be the most elegant—or “Pythonic,” as they say—way to approach the problem. However, it does exactly what I needed.


Source Code

__author__ = "Craig LaBarge WB3GCK"
__email__ = "wb3gck at arrl.net"
__contact__ = "https://wb3gck.com/contact/"
__date__ = "5/03/2019"
__version__ = "v1.1.0"

# This script is used to add my custom tags to ADIFs exported from SKCCLogger or other programs.
# The script expects:
#     Files in ADIF located in the same working directory as the script
#     ADIF files must have a ".adi" or ".adif" extension.


import os
import sys


def listfiles():
    """This function finds all ADIF files in the working directory and prints out a listing with index
    numbers.  It returns a list of available ADIF files."""
    logs = []
    count = 1
    for filename in (os.listdir('.')):
        if '.adi' in filename:
            logs.append(filename)
            print(str(count) + ' - ' + filename)
            count = count + 1
    if not logs:   # Check for empty list; e.g., no PDFs found
        print('')
        print('Ooops! No ADIF files found!!  \nTerminating script...\n')
        sys.exit()
    else:
        print('')
        return logs


print('\n*** add_tags.py ' + __version__ + ' by WB3GCK ***\n')


# Prompt the user for the integer number corresponding to the desired message file.
# Check to make sure the input is within the proper range
good_file = False
file_choice = ''
file_list = listfiles()  # Get a list of ADIF files
file_in = ''
while not good_file:
    file_in = input('Enter the ADIF file number:  ')
    if not file_in.isdecimal():  # Check for non-numeric input
        print('Input must be a numeral!  Try again, Pal!')
        continue
    else:
        file_nr = int(file_in) - 1
    if file_nr < 0 or file_nr > (len(file_list) - 1):  # Check for out of range input
        print('Input out of range.  Better try that again, Bucko.')
    else:
        file_choice = file_list[file_nr]  # Sets the selected file name
        good_file = True

# Check the selected file for the presence of a TX_PWR tag
if ('TX_PWR' in open(file_choice).read()) or ('tx_pwr' in open(file_choice).read()):
    has_pwr = True
else:
    has_pwr = False

# Prompt user for the MY_QTH value
my_qth = input(r'Enter QTH:  ')
qth_tag = '<MY_QTH:' + str(len(my_qth)) + '>' + my_qth + ' '

# Prompt user for MY_RIG value
my_rig = input(r'Enter Rig:  ')
rig_tag = '<MY_RIG:' + str(len(my_rig)) + '>' + my_rig + ' '


# Prompt user for TX_PWR if there is no TX_PWR in the selected file
good_pwr = False
tx_pwr = ''
pwr_tag = ''
if not has_pwr:
    while not good_pwr:
        tx_pwr = input('Enter TX_PWR:  ')
        # Check for numerals and decimal points only
        try:
            val = float(tx_pwr)
            good_pwr = True
        except ValueError:
            print("Hey Bucko! Numerals and decimal points only!!")
    pwr_tag = '<TX_PWR:' + str(len(tx_pwr)) + '>' + tx_pwr + ' '

# Create the replacement tag
if not has_pwr:
    new_tags = qth_tag + rig_tag + pwr_tag + '<EOR>'
else:
    new_tags = qth_tag + rig_tag + '<EOR>'

# Modify the selected ADIF file
file = open(file_choice, 'r')
filedata = file.read()

# Replace the target string
if '<EOR>' in open(file_choice).read():
    filedata = filedata.replace('<EOR>', new_tags)
elif '<eor>' in open(file_choice).read():
    filedata = filedata.replace('<eor>', new_tags)
else:
    print('Are you sure this is a valid ADIF file?? \nTerminating script...')
    sys.exit()

file = open(file_choice, 'w')
file.write(filedata)

print('\nGreat success! ' + file_choice + ' modified.\n')

How to Run It

I run this script on a Windows machine, so this section is focused on that operating system. For Linux and Mac, you might need to do some research.

  • Make sure you have Python 3 installed on your computer. If not, you can get it for free at python.org.
  • Download the script file here and unzip it.
  • Place the ADIF file you want to modify in the same folder as the script file. 
  • Open a command window and navigate to the directory containing the script and ADIF file.
  • Start the script with the command: python add_tags.py. I use a Windows batch file to save having to save some typing. Depending on how Python is installed on your system, you might be able to just double-click the script file.
  • Following the prompts, enter the necessary information. That’s all there is to it.
Screenshot of the add_tag.py script running
Screenshot of the add_tag.py script running

Some Precautions

  • This script doesn’t check to see if you have already modified the ADIF file. If you have, you’ll end up with redundant fields in your ADIF file. Your logging program probably won’t like that.
  • Always keep a backup of your ADIF file or have an easy way to regenerate it. If you make a mistake in one of your inputs, just start over with another copy of the ADIF file.
  • I’ve only included a minimal amount of error checking in the script, so it’s far from bullet-proof. Double-check each input carefully before pressing <ENTER>.

Disclaimers

Of course, no article on software is complete without a disclaimer or two.

  • Use this script at your own risk. It works for me, but I make no guarantees that it will work for you.
  • I can’t offer any technical support or tailor it to your application.

So there you have it. If you find yourself having to routinely add fields to an ADIF file—maybe not, but you never know—feel free to modify this script to suit your needs. It should be easy to adapt it to add other ADIF tags.

If you want to dabble in Python programming, Google is your friend. There are tons of resources out there for learning Python.

73, Craig WB3GCK

The Forgotten Antenna

We’re expecting some snow and sleet tomorrow, so I figured I head out for a little QRP-portable operating before the nasty weather moved in. So, I drove to nearby Black Rock Sanctuary for a quick outing.

The temperature today in southeastern Pennsylvania was a mild 42° F. I planned to operate from a picnic table using my AlexLoop clamped to the table. However, in my haste to get on the road, I neglected to put the AlexLoop in my truck. As Homer Simpson would say, “Doh!”

I had some antenna wires, but I didn’t think it was a good idea to mess with trees in a nature preserve. Fortunately, I always keep the necessary equipment for my stationary-mobile set-up in the truck. With my 19-foot vertical mounted on the back, I operated from inside the truck.  

A view of the "cockpit" of the truck
A view of the “cockpit” of the truck

The bands were in great shape this afternoon. It didn’t take long on 40M to put 5 SKCC contacts in the log. I also had a nice rag chew with K8RQX in Michigan before moving up to 20M.

Up on 20M, I had a coast-to-coast SKCC QSO with WD7JS in Washington. Russ was booming into Pennsylvania and gave my 5-watt signal an “honest 539.” I’ll take it! I moved down to check out 30M and had a quick SKCC QSO with K5MP in Florida before packing up.

Despite my absent-mindedness, It was a nice outing. Next time, I’ll have to pay better attention to my checklist.

72, Craig WB3GCK

Polar Bear Moonlight Madness – November 2019

Although the Polar Bear QRP Club has been around for 13 years, the club hasn’t been very active in recent years. The club’s recent move from Yahoo Groups to groups.io prompted renewed interest among the members.

Mike VE3WMB/VA2NB organized one of the club’s Polar Bear Moonlight Madness Events (PBMME). The PBMME is an informal event where we get on the air—typically outdoors—on a Saturday closest to a full moon.

For today’s PBMME, I drove out to Upper Schuylkill Valley Park near Royersford, PA, one of my favorite portable locations. I was tempted to set up at a picnic table but, with the 39°F temperature (and a windchill of 29°F), I opted to operate from my truck. I went with my usual set up: my homebrew 19-foot vertical mounted on the truck and my KX3 up in the cab.

My operating location in Upper Schuylkill Valley Park for the November 2019 Polar Bear Moonlight Madness Event (PBMME).
My operating location in Upper Schuylkill Valley Park for the November 2019 Polar Bear Moonlight Madness Event (PBMME).

I started on 40M and almost immediately got a call from VA2NB. Mike was operating from his cottage in Quebec. This was the first Polar Bear QSO for each of us in a long time. Unfortunately, Mike would be the only Polar Bear in my log today.

After working Mike, I went on to make another half-dozen QSOs, including a couple of two-way QRP contacts and some nice rag chews. I also picked up a new SKCC number from NC7H Idaho. There were a few other Polar Bears on the air but, sadly, I never heard them.

The Schuylkill River at Upper Schuylkill Valley Park
The Schuylkill River at Upper Schuylkill Valley Park

I was only out for 2 hours but it was a fun time. Thanks to VA2NB for preventing me from getting skunked today. I’m hoping that activity in the Polar Bear QRP Club will continue to grow.

72, Craig WB3GCK

QRPp in the November WES

Years back, I regularly ran QRPp. It’s been a while, so I had some fun getting re-acquainted with QRPp during this month’s SKCC Weekend Sprintathon (WES).

On Saturday, I headed out to Black Rock Sanctuary, one of my favorite spots for a quick stationary-mobile outing. The temperature was in the 30s, so I operated from my truck. I mounted my trusty 19-foot vertical on the back of the truck and set up the KX3 in the cab. I turned the power down to 1 watt and got busy looking for WES stations.

My set up at Black Rock Sanctuary during the November WES
My set up at Black Rock Sanctuary during the November WES

The 40M band seemed to be in good shape, but there were RTTY stations all over the place. Despite the RTTY interference, I didn’t seem to have much difficulty making contacts. I didn’t have as much luck on 20M, but I did pick up two stations (Florida and Georgia).

After an hour and a half, I had to pack up to run some errands. I ended up with 8 contacts in the log. That’s better than I expected.

I didn’t have much time for radio this weekend, but I did pick up a couple more contacts from home on Sunday. It was a bit more of a challenge at home with my rainspout antenna. My final tally was 10.

It never ceases to amaze me what you can do with 1 watt. Thanks the great operators who managed to pull me out of the noise.

72, Craig WB3GCK

Out of the Crypt – Zombie Shuffle 2019

WB3GCK QRP Zombie credentials

Last night was the annual Zombie Shuffle, one of my favorite QRP contests. The QRP zombies weren’t too scary, but the band conditions were frightful.

For the past two years, the Zombie Shuffle coincided with our last camping trip of the year. Since I put my little trailer into hibernation after last week’s trip, I had to operate from home using my meager rainspout antenna.

I tried 20M during daylight hours, but I never heard a single zombie there. The Reverse Beacon Network (RBN) showed I was getting out but not very well. I bagged 4 zombies on 40M, but that was a struggle at times. My noise level was high, signals were weak, and there was a lot of fading. One of those zombies was VE3MGY who was one of the bonus stations with this year’s Titanic theme—MGY was the Titanic’s callsign. I also ran into fellow Polar Bear QRPer, Mike VE3WMB.

Signals were a bit stronger on 80M and I picked up 5 zombies there. For some reason, my rainspout gets out well on that band. Towards the end, though, my KX3 had some issues keeping a match on 80M. I guess that means I need to do some maintenance on the rainspout antenna.

My QRP buddy, Ed WA3WSJ, used the Boschveldt QRP Club callsign (W3BQC) as an MGY bonus station. I was tracking him on RBN but I never heard him. However, I did work a another Boschveldt QRP friend, Glen NK1N. I also ran into an old QRP friend, KA3D. It was great to hear Dan again.

So, with a total of 9 zombies, I didn’t have my best year, but it sure wasn’t my worst. I was only 2 off from last year’s effort in the QRP camper.

Many thanks to Paul NA5N and Jan NØQT for another fun contest.

72, Craig WB3GCK

Wrapping Up Another Camping Season

This is always a bittersweet time of year for me. While I enjoy camping in Fall, I also know that the camping season is drawing to a close. This past weekend was the final trip of the year for the QRP Camper.

My (far) better half and I took our little trailer to nearby French Creek State Park in Elverson, Pennsylvania. We usually start and end the season there. It’s close to home and it’s one of our favorite campgrounds.

The WB3GCK "QRP Camper" as we were wrapping up our last camping trip of the year. We had the unpleasant task of packing up in a steady downpour.
The WB3GCK “QRP Camper” as we were wrapping up our last camping trip of the year. We had the unpleasant task of packing up in a steady downpour.

My radio time was limited this weekend. We had our four grandchildren visit the campsite on Saturday. Most of Saturday was spent carving pumpkins with the kids and roasting hotdogs and marshmallows over the campfire. 

I did manage to find time to make a half-dozen contacts, though. A couple of them were real nice rag chews. One of note was with K1LKP in New Hampshire. Carmen noted that our last QSO was 15 years ago while I was camping in Maryland. It sure was nice to work him again.

Looking back over the past camping season, I made a few small changes in how I operate from the camper. I mentioned in previous posts, that the 120VAC-to-12VDC converter in the trailer generates a huge amount of RF noise. I’ve been getting around that by killing the AC power to camper when I’m on the radio. All of the essential functions in the trailer (lights, refrigerator, water pump, water heater) automatically switch to battery or propane. In the chillier weather—like this weekend—, I run a separate extension cord into the trailer to power a small electric heater.

I also did some experimenting with the way I feed my antenna. My 29.5-foot vertical is fed through 9:1 unun and uses the coax shield as a counterpoise. I have never had any serious problems with RF in the shack, but I have noticed some minor fluctuations in SWR. I placed a common mode choke at the rig end, and that has made tuning more consistent. I built the common mode choke—or line isolator—a while back for other experiments. It’s now a permanent part of my set up in the camper.

This is the hombrew common mode choke that I have been using with my 29.5-foot vertical and 9:1 unun.
This is the hombrew common mode choke that I have been using with my 29.5-foot vertical and 9:1 unun.

So, that wraps up another fun camping season with the QRP Camper. It’s now time to Winterize it and put it in storage until Spring. It’s not the end of my portable operating though; there’s still lots of outdoor radio fun to be had.

72, Craig WB3GCK

POTA and WWFF at Colonel Denning State Park

Our camping season is rapidly drawing to a close. My (far) better half and I took our little camper out to Colonel Denning State Park (POTA K-1343, WWFF KFF-1343) for our next-to-the-last trip of the year.

Located in central Pennsylvania, Colonel Denning was a new park for us. Our campsite for the weekend small but more than adequate. This section of the campground was along a creek and in a valley. There were steep hills directly behind our site. Given the terrain, I didn’t have high hopes for my radio waves getting out.

The WB3GCK "QRP Camper" at Colonel Denning State Park. My antenna is that white object to the rear of the camper.
The WB3GCK “QRP Camper” at Colonel Denning State Park. My antenna is that white object to the rear of the camper.

We arrived on Friday afternoon. After getting the camper situated, I set up my antenna and gave the radio a quick test. Tuning around, I could hear some strong signals. That gave me some hope.

I didn’t get on the air until Saturday morning. It was only 35F overnight, so I hunkered down in the camper to operate. I made a few contacts, so I appeared to be getting out OK. On 40M, I worked WB9WIU in Indiana, some New York QSO Party stations, and had a 2-way QRP QSO with WA1LFD in New Hampshire.

Doubling Gap Creek in Colonel Denning State Park.
Doubling Gap Creek in Colonel Denning State Park near our campsite.

Later in the day, I spotted myself on the POTA and WWFF websites and spent an hour or so working park chasers. I worked a lot of regulars including W6LEN in California. I had park-to-park QSOs on two bands (20M and 17M) with N4CD in Texas. At one point, I received a call from EA2IF in Spain, who mistakenly thought I was a SOTA activator. In any event, I was happy to add him to my log. I ended my brief POTA/WWFF session with 23 stations in the log.

We awoke Sunday morning to a steady rain. According to the local forecast, the day was going to be a washout—they were right. I made one final contact with K9FW on 80M before tearing down and packing up for the trip home.

The bands were in good shape over the weekend. Despite the terrain, my QRP signals seemed to have found their way out of the valley. Colonel Denning is on our list for a return visit next year.

73, Craig WB3GCK