WSJT-XログからTurboHAMLOGへの変換

はじめに

山岳移動運用で使用したタブレットに保存されている、WSJT-XのログデータをTurbo HAMLOGに追加登録できる CSV形式に変換するツール作成しました。ツールはオンラインで変換でき、住所データについては総務省から自動取得し、Turbo HAMLOGのRmks欄に記入する内容も画面上で指定できるようになっています。変換後のダウンロードしたデータはTurboHAMLOGが読み込めるShift_JIS形式です。

また、参考としてローカルで使用できるツールもPythonで作製しましたのでソースリストを掲載しています。

特徴

Webで変換。
 住所は総務省のWebから取得、複数の住所がある場合の識別を付加。
 TurboHAMLOGのRemks欄に該当する項目を入力
 
(変換のページはこちらから  <wsjt-x to Hamlog > )

以下は、Pythonでの内容です。*参考程度のソースリスト

Python3系で作製し、3種類の変換方式のそれぞれのソースコードを公開しているので、自分にあった(ハムログのRemaksの使い方)方式に変更が可能です。

コマンドラインでの動作

単にHmaLogに読み込めるCSV形式に変換するだけでなく、総務省のDBからオンラインで相手局の住所を取得する方式(JSON,CSV)も行っています。

自分のTurbo HAMLOGでは、Remks2に移動運用地点(SOTAコード)を入れているので移動地等はソースコード上で埋め込み、出力するHamlogの入力となるファイル名だけをコマンドラインで指定するようにしました。使ってみてよくなければ適当に直そう。移動運用地(rmks2)はコマンドライン入力でもよかったかも。
 使用は、タブレットに保存されているWSJT-X.logを自宅の通常使用しているPCに移すときに、Logの変換する対象のレコードだけを絞り込んで変換元のファイルにしてから、このツールを実行しています。このあたりも、日付の範囲指定をすればよいのでしょうが、そこまでの作りこみはしませんでした。GUIもないので単なるツールです。
 他にもっとよい方法があるかもしれませんが、pythonの練習には手ごろな題材になりました。ソースリストは公開するほどのものではないのですが、参考程度です。

 

1.Webでの変換

ローカルに保存されているwsjtxのログデータを、Turbo HAMLOGが読み込みできるcsv形式のファイルに変換します。住所データは総務省のWebから自動取得します。Turbo HAMLOGのRemks1,2欄に記入する内容は画面から変換前に入力できます。

変換後のデータはローカルにダウンロードするとShift-JIS形式で保存されますので、そのままTurbo HAMLOGに読み込ませることができます。

仕様

■wsjtのログの時刻等は変更しない。TurboHAMLOGに読み込ませるために時刻にUTCの識別としてUとしている

■コールサインをもとに総務省のWebから住所を取得し、複数の無線局(移動・固定等)が登録されている場合は住所の前に()内に登録局数を付加し、住所は第一レコードの登録住所を取得して付加します。海外局のように、総務省のWebに登録されていない場合は住所は「********」で埋め込みます。

■TurboHAMLOGではRmks1とRmks2欄が使用できるので、変換するときに各欄に入力できます。文字数は40文字までで、<>などの文字はエスケープ処理されます。また、ファイルがCSV形式であるため、Rmks欄に[,]がある場合は[_]に変更しています。

■周波数の変換は、小数点以下の3桁までとして以下を切り捨てています。

■Turbo HAMLOGに読み込ませるときはデータの内容をエディタ等で確認の上実行してください。不具合が発生しても一切の責任は負えません。

変換のページはこちらから  <wsjt-x to Hamlog > 

 Wsjt-x to Hamlog Convert 操作手順 

1.初期画面が表示されるので、「参照」をクリックします。

2.wsjtログのあるファイルを指定して読み込みます。

3.wsjtログのファイルを読み込んだ結果をテキストエリアに表示します。スクロールして内容を確認できます。
  読み込みが正常におこなわれると、Rmks1とRmks2の入力欄と  wsjt->Hamlog  の変換ボタンが表示されます。

5.Hamlog のRmks欄に反映する場合は、Rmaksの各欄に必要な文字を入力します。制限として<&>などの文字はエスケープ処理されます。

  Rmks欄を確認後、 wsjt->Hamlog  をクリックすると、オンラインで総務省の無線局情報にアクセスして住所等を取得して、Hamlogが読み込めるファイルに変換します。 

 

6.変換中は、テキストエリアに変換後のレコードが1件毎に表示されます。すべてのレコードの変換が終了すると、テキストエリアに全変換したレコードが表示されます。変換が終了すると、変換したテキストエリアの下にダウンロードするためのファイル名の入力エリアとダウンロードボタンが表示されます。
ダウンロードファイル名はデフォルトでwjst2hamlog.csvになっています。変更する場合はここでファイル名を変えてください。

7.ダウンロードは変換後のテキストエリアに表示されている内容がそのままローカルにダウンロードされます。
 ダウンロードされたデータはShift-JIS形式のCSVファイルなので、そのままTurboHAMLOGで読み込むことができます。TurboHAMLOGに読み込ませる前には、エディタ等で内容を再確認することをお勧めします。

変換のページはこちらから  <wsjt-x to Hamlog > 

 

 

 

 

2.単にTurboHAMLOGが読み込みできるCSV形式に変更

# -*- coding: utf-8 -*-

#FT8 WSJT-XのログデータからHamlogへ追加入力するCSV形式のファイルを作製する
#2019/12/26 V.01 Copyrigth little-ctc.com 
#python to_hamlog.py outputfile_ID
#sample data
#in:  2019-12-25,06:25:15,2019-12-25,06:26:19,JA1RL,PM96,7.042062,FT8,-03,-10,,,
#out: JA1RL,19/12/25,06:25U,-03,-10,7,FT8,PM96,,J,,,,栃木県日光市 毘沙門山(587m) SOTA:JA/TG-105,48

#入力ファイルはDir FT8のwsjtx.logとする
#出力ファイルはDir Hamlogに指定したファイル名で作製
#使用方法 python to_hamlog.py 1226 
#とすると Hmalogの中にhamlog_1226.csv としてHamlogに入力できるファイルが作成される

import sys
import csv

#入力レコードのカラム位置
SDATE=0
STIME=1
UCALL=4
GL=5
FRQ=6
MODE=7
USNR=8
MSNR=9

rmks1 = ""  #rmks2に反映する内容
rmks2 = "栃木県日光市 毘沙門山(587m) SOTA:JA/TG-105" #移動地を入力する rmks2に反映する

outf_name= ".\\hamlog\\hamlog_%s.csv" % (sys.argv[1])
print("出力ファイル:",outf_name)
r_cnt = 0
with open(outf_name,'wt') as fout:
    inf_name= ".\\ft8\\wsjtx.log"
    with open(inf_name,'rt') as fin:
            csv_reader = csv.reader(fin,delimiter=',')
            for col in csv_reader:
                if col[0][0] != '#':
                    r_cnt +=1
                    ymd = col[SDATE].replace("-","/")[2:10]
                    st_time = col[STIME][0:5]+'U'
                    frq = col[FRQ].split(".")
                    fout.write("%s,%s,%s,%s,%s,%s,%s,%s,,J,,,%s,%s,48\n" % ( col[UCALL],ymd,st_time,col[USNR],col[MSNR],frq[0],col[MODE],col[GL],rmks1,rmks2) )
    print("出力レコード2:",r_cnt)
#read

 

3.住所データとJARL会員情報を付加

 ハムログにインポートするときに、相手の住所が空欄となってしまうので、ネットにある総務省のデータとJARLのデータを統合したリスト(一括CSVファイル)から住所とJARL会員の情報を付加するように変更してみました。
 JARLの会員処理が複雑になってしまいましたが、固定と移動などの同一コールで複数の免許を取得している場合に、JARLの会員がどちらか一つに一括CSVファイルがなっているためです。したがって、同一コールで登録している住所が違う場合はJARL会員登録の住所がセットされます。(2020/01/14 追記)

 ハムログ内の機能(免許状Get’s)を使うことでリアルタイムに住所やJARL会員情報が取得できますので実用性は?ですが、プリプロセスとして使ってみよう。

・GLの位置がズレていたので修正<2020/03/03>

・移動した場合にコールサインに後に付く「/1」や「/P」が付加されている場合に、「/」前までをコールサインとして認識するように修正しました<2020/2/4>

 

# -*- coding: utf-8 -*-

#FT8 WSJT-XのログデータからHamlogへ追加入力するCSV形式のファイルを作製する
#ネットに公開されている簡易版コールブックのデータから住所を付加し、JARLの入会を付加
#JARL入会メンバは住所の先頭に「〇」、未加入は「☆」を付加
#簡易版コールブックデータ https://jj1wtl.at.webry.info/201901/article_11.html
#全局データのcvsファイルを利用:offline-callbook-ja-20190109.csv
#2020/01/14 V.02 Copyrigth little-ctc.com 
#python to_hamlog.py outputfile_ID
#sample data
#call_book: JA1RL,*****,東京都〇〇区,平30.9.6,A,0003699261,50,1,JARL,,
#in:  2019-12-25,06:25:15,2019-12-25,06:26:19,JA1RL,PM96,7.042062,FT8,-03,-10,,,
#out: JA1RL,19/12/25,06:25U,-03,-10,7,FT8,PM96,,J,名前,住所,,栃木県日光市 毘沙門山(587m) SOTA:JA/TG-105,48

#入力ファイルはDir FT8のwsjtx.logとする

#出力ファイルはDir Hamlogに指定したファイル名で作製
#使用方法 python to_hamlog.py 1226 
#とすると Hmalogの中にhamlog_1226.csv としてHamlogに入力できるファイルが作成される

import sys
import csv

#CallBook_data
C_CALL=0
C_ADR=2
C_JARL=8

#入力レコードのカラム位置
SDATE=0
STIME=1
UCALL=4
GL=5
FRQ=6
MODE=7
USNR=8
MSNR=9

rmks1 = ""  #rmks2に反映する内容
rmks2 = "HOME 松戸市" #移動地を入力する rmks2に反映する

adr_dic = {}
jarl_dic = {}
callf_name = ".\\ft8\\offline-callbook-ja-20190109.csv"
with open(callf_name,'rt') as fin:
    csv_reader = csv.reader(fin,delimiter=',')
    for col in csv_reader:
        if col[C_CALL] in adr_dic :
            if col[C_JARL] == "JARL":
                adr_dic[col[C_CALL]] = "〇" + col[C_ADR]

        else:
            if col[C_JARL] == "JARL":
                adr_dic[col[C_CALL]] = "〇" + col[C_ADR]
            else:
                adr_dic[col[C_CALL]] = "☆" + col[C_ADR]

outf_name= ".\\hamlog\\hamlog_%s.csv" % (sys.argv[1])
print("出力ファイル:",outf_name)
r_cnt = 0
with open(outf_name,'wt') as fout:
    inf_name= ".\\ft8\\wsjtx.log"
    with open(inf_name,'rt') as fin:
            csv_reader = csv.reader(fin,delimiter=',')
            for col in csv_reader:
                if col[0][0] != '#':
                    callsig = col[UCALL].split("/")
                    r_cnt +=1
                    if callsig[0] not in adr_dic:
                        adr_dic[callsign[0]] = "********"
                    ymd = col[SDATE].replace("-","/")[2:10]
                    st_time = col[STIME][0:5]+'U'
                    frq = col[FRQ].split(".")
                    fout.write("%s,%s,%s,%s,%s,%s,%s,,%s,J,,%s,%s,%s,48\n" % ( col[UCALL],ymd,st_time,col[USNR],col[MSNR],frq[0],col[MODE],col[GL],adr_dic[callsig[0]],rmks1,rmks2) )
    print("出力レコード2:",r_cnt)
#read

 

4.住所データを総務省Webからオンライン取得(JSON形式)

住所の取得を総務省のWebから取得するように変更してみました。総務省のWebからは、CSV、JSON、XMLの各型式で取得できます。今回はJSON形式で取得してみました。pythonの練習として作製してみましたのであまり参考になりませんが、備忘録として公開します。 <2020/03/03>

# -*- coding: utf-8 -*-

#FT8 WSJT-XのログデータからHamlogへ追加入力するCSV形式のファイルを作製する
#取得する住所データは総務省のWebから取得する。未登録のコールサインは住所を********で表示
#複数の登録がある場合は住所の先頭に複数の登録局数を()内に追加表示する
#2020/03/03 V.01 Copyrigth little-ctc.com 
#python to_jsonlog.py outputfile_ID
#sample data
#in:  2019-12-25,06:25:15,2019-12-25,06:26:19,JA1RL,PM96,7.042062,FT8,-03,-10,,,
#out: JA1RL,19/12/25,06:25U,-03,-10,7,FT8,PM96,,J,名前,住所,,栃木県日光市 毘沙門山(587m) SOTA:JA/TG-105,48
#同一コールサインで複数の無線局が登録されている場合は、住所は最初のレコードから取得して、住所の先頭に()で登録数を追記

#入力ファイルはDir FT8のwsjtx.logとする

#出力ファイルはDir Hamlogに指定したファイル名で作製
#使用方法 python to_jsonlog.py 1226 
#とすると Hmalogディレクトリの中にhamlog_1226.csv としてHamlogに入力できるファイルが作成される

import sys
import csv
import requests
import json

#CallBook_data
C_CALL=0
C_ADR=2
C_JARL=8

#入力レコードのカラム位置
SDATE=0
STIME=1
UCALL=4
GL=5
FRQ=6
MODE=7
USNR=8
MSNR=9

#総務省Webの情報取得パラメータ一覧 JSONを指定
#ST=1 免許情報検索
#OF 出力形式 1:CSV 2:JSON 3:XML
#DA 詳細情報付加 0:付加しない 1付加する:
#OW 無線局の種別 AT:アマチュア無線
#DC 取得件数 1:100件 
#SC スタートカウント 取得件数を指定
#MA 呼び出し符号(コールサイン)


rmks1 = ""  #rmks2に反映する内容
#rmks2 = "HOME 松戸市" #移動地を入力する rmks2に反映する
rmks2 = "茨城県つくば市 筑波山(878m) SOTA:JA/IB-003" #移動地を入力する rmks2に反映する

#----------

outf_name= ".\\hamlog\\hamlog_%s.csv" % (sys.argv[1])
print("出力ファイル:",outf_name)
r_cnt = 0
c_adr=""
with open(outf_name,'wt') as fout:
    inf_name= ".\\ft8\\wsjtx.log"
    with open(inf_name,'rt') as fin:
            csv_reader = csv.reader(fin,delimiter=',')
            for col in csv_reader:
                if col[0][0] != '#':
                    callsig = col[UCALL].split("/")
                    #総務省のWebから免許情報を取得して、住所を得る 複数ある場合は第一だけ
                    s_data = "https://www.tele.soumu.go.jp/musen/list?ST=1&SK=2&OF=2&DA=0&OW=AT&DC=1&SC=1&MA=%s" % (callsig[0])
                    res= requests.get(s_data)
                    jdata = json.loads(res.text)

                    if(jdata["musenInformation"]["totalCount"] == "0"): #登録されている局数を取得 コールが未登録は「0」となる
                        c_adr = "********"
                    elif (jdata["musenInformation"]["totalCount"] == "1"):
                        c_adr =jdata["musen"][0]["listInfo"]["tdfkCd"] #複数あっても第一レコードから住所を取得
                    elif (jdata["musenInformation"]["totalCount"] > "1"):
                        c_adr = "(%s)%s" % (jdata["musenInformation"]["totalCount"], jdata["musen"][0]["listInfo"]["tdfkCd"])
                    #c_adr = adr_dic[callsig[0]] + c_adr
                    print(callsig[0],":",c_adr) #Webからのデータ取得は時間がかかるので途中の処理状況を表示する

                    r_cnt +=1
                    ymd = col[SDATE].replace("-","/")[2:10]
                    st_time = col[STIME][0:5]+'U'
                    frq = col[FRQ].split(".")
                    fout.write("%s,%s,%s,%s,%s,%s,%s,,%s,J,,%s,%s,%s,48\n" % ( col[UCALL],ymd,st_time,col[USNR],col[MSNR],frq[0],col[MODE],col[GL],c_adr,rmks1,rmks2) )
    print("出力レコード2:",r_cnt)
#read

補足

JSON形式でのデータ取得は、例えばコールサインを「JA1YRL」で指定すると

{
    "musen": [
        {
            "listInfo": {
                "name": "一般社団法人日本アマチュア無線連盟(JA1YRL)",
                "radioStationPurpose": "アマチュア業務用",
                "tdfkCd": "東京都豊島区",
                "no": "1",
                "licenseDate": "2018-03-16"
            }
        }
    ],
    "musenInformation": {
        "totalCount": "1",
        "lastUpdateDate": "2020-03-01"
    }
}

のようなJSON形式の情報が取得できます。ここで、 “listInfo”は複数の登録があると複数繰り替えされます。
musenInformationの ”totalCount” に登録されているデータ数がセットされています。この例では登録が1の場合です。固定と移動の両方を登録されている場合は2個になります。通常は1か2ですが、まれに別場所に開設している場合は4とかもありました。上記の例は、住所情報だけを取得しているので少ない情報を得ていますが、詳細な情報も得ることができます。

5.住所データを総務省Webからオンライン取得(CSV形式)

前項では総務省Webからの取得をJSON形式で行いました。下記の例は、CSV形式で取得した場合の記述例です。データ量が少ない指定での取得なので、JSONのほうがスマートに感じます。CSV形式ではファイルでダウンロードしてから各データを取得する方式にしてみました。今回のようにデータ量が少ないい場合はあまりメリットはないようです。

データ量が少ないので、すこし強引に1レコードにする方法もあります。どちらでも、単にコールサインに対する住所だけを取得するならばJSON形式ですね。

リスト (ファイル保存スタイル)

# -*- coding: utf-8 -*-

#FT8 WSJT-XのログデータからHamlogへ追加入力するCSV形式のファイルを作製する
#総務省Webからオンラインでコールサインに対する住所をCSVファイル形式で習得する 
#Webから一旦ファイルで保存してから解析する方式で記述。1コールサインに対する処理ならば、JSON形式が簡単
#2020/03/04 V.01 Copyrigth little-ctc.com 
#python to_csvf.py outputfile_ID
#sample data
#in:  2019-12-25,06:25:15,2019-12-25,06:26:19,JA1RL,PM96,7.042062,FT8,-03,-10,,,
#out: JA1RL,19/12/25,06:25U,-03,-10,7,FT8,PM96,,J,名前,住所,,栃木県日光市 毘沙門山(587m) SOTA:JA/TG-105,48

#入力ファイルはDir FT8のwsjtx.logとする

#出力ファイルはDir Hamlogに指定したファイル名で作製
#使用方法 python to_csvf.py 1226 
#とすると Hmalogディレクトリの中にhamlog_1226.csv としてHamlogに入力できるファイルが作成される

import os
import sys
import csv
import requests
import urllib


#入力レコードのカラム位置
SDATE=0
STIME=1
UCALL=4
GL=5
FRQ=6
MODE=7
USNR=8
MSNR=9
dfname = 'work.txt'

rmks1 = ""  #rmks2に反映する内容
#rmks2 = "HOME 松戸市" #移動地を入力する rmks2に反映する
rmks2 = "茨城県つくば市 筑波山(878m) SOTA:JA/IB-003" #移動地を入力する rmks2に反映する

#----------

def download_file(url, dst_path):
    try:
        with urllib.request.urlopen(url) as web_file, open(dst_path, 'wb') as local_file:
            local_file.write(web_file.read())
    except urllib.error.URLError as e:
        print(e)


outf_name= ".\\hamlog\\hamlog_%s.csv" % (sys.argv[1])
print("出力ファイル:",outf_name)
r_cnt = 0
c_adr=""

with open(outf_name,'wt') as fout:
    inf_name= ".\\ft8\\wsjtx.log"
    with open(inf_name,'rt') as fin:
            csv_reader = csv.reader(fin,delimiter=',')
            for col in csv_reader:
                if col[0][0] != '#':
                    callsig = col[UCALL].split("/")
                    s_data = "https://www.tele.soumu.go.jp/musen/list?ST=1&SK=2&OF=1&DA=0&OW=AT&DC=1&SC=1&MA=%s" % (callsig[0])
                    res= requests.get(s_data)
                    #print(res.headers['Content-Type'])
                    download_file(s_data,dfname)
                    with open(dfname,'rt',encoding='utf-8') as fin:
                        din = fin.readlines()
                        d1 = din[0].replace("\"","").split(",")
                        d2 = din[1].replace("\"","").split(",")
                        icnt = d1[1].strip()

                        if (icnt == "0"):
                            c_adr = "********"
                        elif (icnt == "1"):
                            c_adr = d2[2]
                        elif (icnt > "1"):
                            c_adr = "(%s)%s" % (icnt,d2[2])

                    print(callsig[0],":",c_adr)

                    r_cnt +=1
                    ymd = col[SDATE].replace("-","/")[2:10]
                    st_time = col[STIME][0:5]+'U'
                    frq = col[FRQ].split(".")
                    fout.write("%s,%s,%s,%s,%s,%s,%s,,%s,J,,%s,%s,%s,48\n" % ( col[UCALL],ymd,st_time,col[USNR],col[MSNR],frq[0],col[MODE],col[GL],c_adr,rmks1,rmks2) )
    print("出力レコード2:",r_cnt)
os.remove(dfname)


 


6.実行例

実行例
下記のwsjt-xのログを読み込ませると

2020-03-01,00:07:30,2020-02-01,00:08:24,JX1IFK,PM95,144.461129,FT8,-12,-17,,,
2020-03-01,00:11:00,2020-02-01,00:11:30,JX1SWZ,QM05,144.461129,FT8,-12,-13,,,
2020-03-01,00:21:11,2020-02-01,00:22:57,JX2HZA,PM94,144.461129,FT8,-04,-12,,,
2020-03-01,00:24:00,2020-02-01,00:24:46,JX1MSY,PM95,144.461129,FT8,-02,-08,,,
2020-03-01,00:30:00,2020-02-01,00:31:59,JX9GGO,PM86,7.042098,FT8,-04,+05,,,
2020-03-01,00:32:30,2020-02-01,00:33:06,JX3JZJ,PM74,7.042098,FT8,+09,-07,,,

 このような住所を付加したハムログ読み込み可能なCSVファイルが作成されます。住所の前の()内の数値は、複数の登録地が存在することを示しています。remks欄はソース内で指定、例では筑波山での運用。 *コールサインはダミーです。

JX1IFK,20/02/01,00:07U,-12,-17,144,FT8,,PM95,J,,(2)東京都八王子市,,茨城県つくば市 筑波山(878m) SOTA:JA/IB-003,48
JX1SWZ,20/02/01,00:11U,-12,-13,144,FT8,,QM05,J,,千葉県千葉市緑区,,茨城県つくば市 筑波山(878m) SOTA:JA/IB-003,48
JX2HZA,20/02/01,00:21U,-04,-12,144,FT8,,PM94,J,,(2)静岡県静岡市駿河区,,茨城県つくば市 筑波山(878m) SOTA:JA/IB-003,48
JX1MSY,20/02/01,00:24U,-02,-08,144,FT8,,PM95,J,,神奈川県横浜市青葉区,,茨城県つくば市 筑波山(878m) SOTA:JA/IB-003,48
JX9GGO,20/02/01,00:30U,-04,+05,7,FT8,,PM86,J,,(2)富山県高岡市,,茨城県つくば市 筑波山(878m) SOTA:JA/IB-003,48
JX3JZJ,20/02/01,00:32U,+09,-07,7,FT8,,PM74,J,,兵庫県高砂市,,茨城県つくば市 筑波山(878m) SOTA:JA/IB-003,48

 

お問い合わせは下記にお願いします