はじめに
本稿は以下記事の続きになります。
概要
本稿では、前回作成したアマチュア無線のログCSV(独自形式)から、ロギングツール「AirHamLog」にインポートするためのCSVを出力するプログラムを紹介します。
開発環境
- macOS Ventura 13.4
- Python 3.11.4
- Visual Studio Code 1.80.1
AirHamLogとは
AirHamLogはブラウザで動作するアマチュア無線/ライセンスフリー無線のロギングツールです。ブラウザベースのためOSに依存せず、ネットワークさえあればどこでもログにアクセスすることができるため、Macユーザーの私も使っています。Android/iOSアプリもリリースされており、スマートフォンやタブレットからも利用することができます。
このAirHamLogですが、ログを手動で追加するだけでなく、CSVやADIFでのインポート/エクスポートに対応しています。数件の交信なら手動で追加してもいいのですが、まとめて追加したいときに便利です。このインポート用のCSVを今回は変換生成してみようと思います。
ログCSVの形式
元のログCSVはこのような形式です。前回の記事でExcelブックからCSVへ変換出力しています。
id,DATE,TIME(JST),frequency,mode,callsign,sent_rst,received_rst,received_qth,received_qra,is_qsl_sent,card_remarks,remarks_1,sent_qth,remarks_2,
1,2023-01-01,12:34,430MHz,FM,JA1RL,59,51,東京都豊島区,鈴木さん,false,Bureau,QSOパーティ,東京都足立区,,
2,2023-04-05,20:16,144MHz,FM,JA7YAB/7,59,59+,山形県天童市,佐藤さん,True,Direct,山形県山形市,偶然,
AirHamLog形式CSVについて
AirHamLogにインポートするCSVにはいくつか要件があります。公式ページに記載があり、各自参照いただきたいのですが、ちょっと手間のかかる作業として、 "交信時刻をISO8601記法に直す" というものがあります。この作業の煩雑さを改善するためにも、自動化してみました。他にも、移動局の場合のコールサインとスラッシュ以下を分割したりしています。
出力したAirHamLog形式CSV
交信年月日・時刻をISO8601記法に直すなど必要な処理を施したものが以下のCSVになります。
id,callsign,portable,qso_at,sent_rst,received_rst,sent_qth,received_qth,received_qra,frequency,mode,card,remarks
1,JA1RL,,20230101T123400+0900,59,51,東京都豊島区,東京都足立区,鈴木さん,430MHz,FM,JARL,QSOパーティ
2,JA7YAB,7,20230405T201600+0900,59,59,山形県天童市,山形県山形市,佐藤さん,144MHz,FM,Direct,偶然
実装例
# log_convert.pyで加工・出力したcsvをAirHamlog用に再加工・出力するプログラム
import csv
import datetime
import glob
import os
import pathlib
import re
# 作業フォルダ内のログCSV一覧取得
logs = glob.glob("../convert_log/prep/*.csv")
logs.sort(reverse=True)
log_path = logs[0]
def rst_convert(mode,rst_num):
# コンテストナンバー等が含まれている場合にRSTレポートのみにする
if mode == "AM" or "FM" or "SSB":
if len(rst_num) > 2:
rst_num = rst_num[:2]
else:
pass
else:
if len(rst_num) > 3:
rst_num = rst_num[:3]
else:
pass
return rst_num
def qth_convert(qth):
if qth[-1] == ")":
hash_mark = re.search("#",qth).start()
qth = qth[:hash_mark-1]
else:
pass
return qth
# ログ読み込み
with open(f"{log_path}", mode="r", encoding="utf-8") as f:
reader = csv.reader(f)
output = []
for i,row in enumerate(reader):
if i != 0:
# QSOの通し番号
id_ = row[0]
# 日付と時刻を結合
date_time = f"{row[1]} {row[2]}" + ":00"
# 日時の文字列を時刻に変換
jst_time = datetime.datetime.strptime(date_time, "%Y-%m-%d %H:%M:%S")
# 書式変更
jst_time = jst_time.strftime("%Y%m%d%H%M%S")
qso_at = jst_time[0:8] + "T" + jst_time[8:] + "+0900"
# 周波数に単位を追加
frequency = row[3]
frequency = frequency + "MHz"
# 電波型式
mode = row[4]
# コールサイン
callsign = row[5]
# ポータブル局ならコールサインとエリアを分割
if callsign[-2] == "/":
portable = callsign[-1]
callsign = callsign[:-2]
else:
portable = ""
# 送信したRSTレポート
sent_rst = rst_convert(mode,row[6])
# 受信したRSTレポート
received_rst = rst_convert(mode,row[7])
# 送信したQTH
if len(row[13]) == 0:
sent_qth = ""
else:
sent_qth = qth_convert(row[13])
# 受信したQTH
if len(row[8]) == 0:
received_qth = ""
else:
received_qth = qth_convert(row[8])
# 受信したQRA
if len(row[9]) == 0:
received_qra = ""
else:
received_qra = row[9]
# カードは未発送ステータスにしておく
if row[10] == "no QSL":
card = "No Card"
else:
card = "JARL"
# 備考欄
if len(row[12]) == 0:
if len(row[14]) == 0:
remarks = ""
else:
remarks = row[14]
else:
if len(row[14]) == 0:
remarks = row[12]
else:
remarks = row[12] + "、" + row[14]
data_l = [id_,callsign,portable,qso_at,sent_rst,received_rst,sent_qth,received_qth,received_qra,frequency,mode,card,remarks]
output.append(data_l)
# 作成日時を付加したCSVを新たに作成
datetime_now = datetime.datetime.now()
now_str = datetime_now.strftime("%Y%m%d%H%M")
# ディレクトリがなかったら新規作成、すでに存在していてもエラーは出ない
pathlib.Path("../convert_log/AHL/").mkdir(exist_ok=True)
conv_file = f"../convert_log/AHL/{now_str}_airhamlog_formatted.csv"
with open(conv_file, mode="w", encoding="utf-8") as p:
# 変更したheaderを書き込み
log_header = "id,callsign,portable,qso_at,sent_rst,received_rst,sent_qth,received_qth,received_qra,frequency,mode,card,remarks\n"
p.write(log_header)
writer = csv.writer(p)
# 元のheaderは書き込まない
writer.writerows(output)
おわりに
次回は最終回の予定、ログCSVからPOTA用ADIFへの変換について執筆する予定です