0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Python]アマチュア無線のログをCSVやADIFに変換してみた(2)ログCSVからAirHamLog形式CSVへ

Posted at

はじめに

 本稿は以下記事の続きになります。

概要

 本稿では、前回作成したアマチュア無線のログ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へ変換出力しています。

log.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になります。

202310161534_airhamlog_formatted.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,偶然

実装例

log2AHL.py
# 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への変換について執筆する予定です

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?