wsjtx2sota (Log-Converter wsjtx.log ==> sota.csv)

for all of you who use FT8 (wsjtx) and SOTA:
I have written a python script to convert wsjtx.log to SOTA formatted csv-file.
This .csv-file you can upload into SOTA-DB.
How to use:
On summit put your Summit-ID into the Commends Field in the Log QSO window of wsjtx
image
Back home start the Python script (below)
You will be asked for your call sign
image
Enter your call sign. then in the next window open your wsjtx.log file
image
select or create an output-file for the SOTA-format-log
image
This file you will import into the SOTA-DB as csv-file
After the format-conversation wsjtx2sota-script displays records with errors.
image
If you close this window. An editor-window of the previous saved SOTA-log opens. Here you can do some fine-tuning.
image
Tip: erase wsjtx.log after upload. (Then you have no duplicate entries)

I have tested the python 3-script on Win10 and Ubuntu. You should adjust your favorite editor in the first 3 lines. (I hope, it runs also on your machine…)

# V 1.1
# define your preferred editor
EDITOR_Windows  ="notepad.exe"
EDITOR_Darwin   ="TextEdit" # not tested
EDITOR_Linux    ="mousepad" #(Ubuntu)

from tkinter import *
from tkinter import filedialog
import os
import subprocess
import platform

CFG             =os.path.dirname(os.path.abspath(__file__))+os.path.sep+"wsjtx2sota.cfg"
MY_CALL_SIGN    ="myCallSign"
INIT_DIR_WSJTX  ="InitDirWsjtx"
INIT_DIR_SOTA   ="InitDirSota"
reg={MY_CALL_SIGN:"DL/HB9HCI/P", INIT_DIR_SOTA:"", INIT_DIR_WSJTX:""}  # default settings

Error="Summit (last field) should be like: HB/BE-151\n"

def GoOn():
    reg[MY_CALL_SIGN]=entryCall.get()
    root.destroy()
    
try: # get settings
    fobjReg = open (CFG) 
    for line in fobjReg :
        if line.find("=")>0 :
            line=line.split("=",maxsplit=1)
            if len(line)==2 :
                if line[0] in reg :
                    reg[line[0]]=line[1][:-1]
    fobjReg.close()
except FileNotFoundError: pass    

root = Tk(className="Wsjtx2Sota")
root.geometry("400x100+600+400")

labelCall = Label(root, text="My Callsign like: DL/HB9HCI/P\n")
labelCall.pack( side = TOP)

default = StringVar(root, value=reg[MY_CALL_SIGN])
entryCall=Entry(root, bd =2, textvariable = default)
entryCall.pack(side = TOP)
btnOk=Button(root,text="Ok", command=GoOn)
btnOk.pack(side=TOP)
root.mainloop()
root = Tk(className="Wsjtx2Sota")

#get wsjtx.loginitDir = get_reg("InitDir")
filename=filedialog.askopenfilename(initialdir=reg[INIT_DIR_WSJTX],title="Select wsjtx.log", filetypes=(("log","*.log"),("all files","*.*")))
if len(filename)==0: 
    exit()
reg[INIT_DIR_WSJTX]=os.path.dirname(filename) # save initial Dir

#output to file (sota.csv)
filenameSota=filedialog.asksaveasfilename(initialdir=reg[INIT_DIR_SOTA],title="Select sota.csv", defaultextension = ".csv", filetypes=(("Comma separated file","*.csv"),("all files","*.*")))
if len(filenameSota)==0: 
    exit()
reg[INIT_DIR_SOTA]=os.path.dirname(filenameSota) # save initial Dir

if filenameSota.upper().find(".CSV") == 0 :
    filenameSota+=".csv"

#loop the lines in wsjtx.log, decode it and write it to ouput
fobj = open(filename, "r")
fobjSota = open (filenameSota,"w")
QSOCount=0
QSOBad=0
for line in fobj:
    if line.find(",")>0 : #skip empty line
        line=line.split(",")
        if len(line)>10 : # skip line with missing fields
            StartDate=line[0]
            StartDate=StartDate.split("-")
            StartDate=StartDate[2] + "/" + StartDate[1] + "/" + StartDate[0]
            StartTime=line[1]
            StartTime=StartTime.split(":")
            StartTime=StartTime[0]+StartTime[1]
            CallSign =line[4]
            Freq     =line[6].split(".")
            Freq     =Freq[0] +"MHz"
            Mode     =line[7]
            Send     =line[8]
            Receive  =line[9]
            Power    =line[10]
            Summit   =line[11] #Summit has to be in Commend-field like: HB/BE-151
            WsjtxLine="V2," + reg[MY_CALL_SIGN] + "," + Summit.upper() + "," + StartDate + "," + StartTime + "," + Freq +",DATA," + CallSign + ",," \
                + Mode + " S:" + Send +" R:" + Receive + " "+ Power + "\n"
            if Summit.find("/") > 0 and Summit.find("-") >0 :
                fobjSota.write (WsjtxLine)
                QSOCount+=1
            else :
                fobjSota.write ("ERROR: "+WsjtxLine)
                Error+=WsjtxLine
                QSOBad+=1
fobj.close()
fobjSota.close()

fobjReg = open(CFG,"w") #save CFG
for line in reg :
    fobjReg.write(line +"="+reg[line]+os.linesep)
fobjReg.close()

errLabel=Text(root) # display results
errLabel.pack()
txtLabel="My Callsign: " + reg[MY_CALL_SIGN] + "\n" + str(QSOCount) + " QSO(s) converted\n"
if QSOBad>0 :
    txtLabel+=str(QSOBad) + " QSO(s) have bad summit-format\n"+ Error
errLabel.insert(END,txtLabel)
root.mainloop()

editor="" # finally call editor with sota-file
if platform.system()    == "Linux"  : 
    editor  =EDITOR_Linux
elif platform.system()  == "Darwin" : 
    editor  =EDITOR_Darwin
elif platform.system()  == "Windows": 
    editor  =EDITOR_Windows
if editor != "": 
    subprocess.call(editor + " " + filenameSota,shell=True)

73 de HB9HCI, Andreas

3 Likes

Is FT8 legal on SOTA activations?
John VE3IPS

Why wouldn’t it be?

Today we (Jürg HB9BIN/P and I) performed our 1st S2S-QSO in FT8: Time to add this feature to wsjtx2sota.py

Enter the Summit and the S2S in the wsjt-x comment-field (Log QSO):
Summit>S2S
(see examble below)
Comment
Here is the updated code:


#!/usr/bin/env python3
# V 1.3
# define your preferred editor
EDITOR_Windows  ="notepad.exe"
EDITOR_Darwin   ="TextEdit" # not tested
EDITOR_Linux    ="mousepad" #(Ubuntu)

from tkinter import *
from tkinter import filedialog
import os
import subprocess
import platform

CFG             =os.path.dirname(os.path.abspath(__file__))+os.path.sep+".wsjtx2sota.cfg"
MY_CALL_SIGN    ="myCallSign"
INIT_DIR_WSJTX  ="InitDirWsjtx"
INIT_DIR_SOTA   ="InitDirSota"
reg={MY_CALL_SIGN:"DL/HB9HCI/P", INIT_DIR_SOTA:"", INIT_DIR_WSJTX:""}  # default settings

Error="Summit (last field) should be like: HB/BE-151\n"

def GoOn():
    reg[MY_CALL_SIGN]=entryCall.get()
    root.destroy()
    
try: # get settings
    fobjReg = open (CFG) 
    for line in fobjReg :
        if line.find("=")>0 :
            line=line.split("=",maxsplit=1)
            if len(line)==2 :
                if line[0] in reg :
                    reg[line[0]]=line[1][:-1]
    fobjReg.close()
except FileNotFoundError: pass    

root = Tk(className="Wsjtx2Sota")
root.geometry("400x100+600+400")

labelCall = Label(root, text="My Callsign like: DL/HB9HCI/P\n")
labelCall.pack( side = TOP)

default = StringVar(root, value=reg[MY_CALL_SIGN])
entryCall=Entry(root, bd =2, textvariable = default)
entryCall.pack(side = TOP)
btnOk=Button(root,text="Ok", command=GoOn)
btnOk.pack(side=TOP)
root.mainloop()
root = Tk(className="Wsjtx2Sota")

#get wsjtx.loginitDir = get_reg("InitDir")
filename=filedialog.askopenfilename(initialdir=reg[INIT_DIR_WSJTX],title="Select wsjtx.log", filetypes=(("log","*.log"),("all files","*.*")))
if len(filename)==0: 
    exit()
reg[INIT_DIR_WSJTX]=os.path.dirname(filename) # save initial Dir

#output to file (sota.csv)
filenameSota=filedialog.asksaveasfilename(initialdir=reg[INIT_DIR_SOTA],title="Select sota.csv", defaultextension = ".csv", filetypes=(("Comma separated file","*.csv"),("all files","*.*")))
if len(filenameSota)==0: 
    exit()
reg[INIT_DIR_SOTA]=os.path.dirname(filenameSota) # save initial Dir

if filenameSota.upper().find(".CSV") == 0 :
    filenameSota+=".csv"

#loop the lines in wsjtx.log, decode it and write it to ouput
fobj = open(filename, "r")
fobjSota = open (filenameSota,"w")
QSOCount=0
QSOBad=0
for line in fobj:
    if line.find(",")>0 : #skip empty line
        line=line.split(",")
        if len(line)>10 : # skip line with missing fields
            StartDate=line[0]
            StartDate=StartDate.split("-")
            StartDate=StartDate[2] + "/" + StartDate[1] + "/" + StartDate[0]
            StartTime=line[1]
            StartTime=StartTime.split(":")
            StartTime=StartTime[0]+StartTime[1]
            CallSign =line[4]
            Freq     =line[6] +"MHz" 
            Mode     =line[7]
            Send     =line[8]
            Receive  =line[9]
            Power    =line[10]
            Summit   =line[11] #Summit has to be in Commend-field like: HB/BE-151>HB/BE-101
            Summit=Summit.split(">")
            if len(Summit)==1:
                Summit=[Summit[0],""]
            WsjtxLine="V2," + reg[MY_CALL_SIGN] + "," + Summit[0].upper() + "," + StartDate\
                + "," + StartTime + "," + Freq +",DATA," + CallSign + ","+Summit[1].upper()+"," \
                + Mode + " S:" + Send +" R:" + Receive + " "+ Power + "\n"
            if Summit[0].find("/") > 0 and Summit[0].find("-") >0 :
                if Summit[1]!="":
                    if Summit[1].find("/") > 0 and Summit[1].find("-") >0 :
                        fobjSota.write (WsjtxLine)
                        QSOCount+=1
                    else:
                        fobjSota.write ("ERROR S2S: "+WsjtxLine)
                        Error+=WsjtxLine
                        QSOBad+=1
                else:
                    fobjSota.write (WsjtxLine)
                    QSOCount+=1
            else :
                fobjSota.write ("ERROR: "+WsjtxLine)
                Error+=WsjtxLine
                QSOBad+=1
fobj.close()
fobjSota.close()

fobjReg = open(CFG,"w") #save CFG
for line in reg :
    fobjReg.write(line +"="+reg[line]+os.linesep)
fobjReg.close()

errLabel=Text(root) # display results
errLabel.pack()
txtLabel="My Callsign: " + reg[MY_CALL_SIGN] + "\n" + str(QSOCount) + " QSO(s) converted\n"
if QSOBad>0 :
    txtLabel+=str(QSOBad) + " QSO(s) have bad summit-format\n"+ Error
errLabel.insert(END,txtLabel)
root.mainloop()

editor="" # finally call editor with sota-file
if platform.system()    == "Linux"  : 
    editor  =EDITOR_Linux
elif platform.system()  == "Darwin" : 
    editor  =EDITOR_Darwin
elif platform.system()  == "Windows": 
    editor  =EDITOR_Windows
if editor != "": 
    subprocess.call(editor + " " + filenameSota,shell=True)

Yes.