Package: azarashi
AzarashiA QZSS DCR Decoder.Descriptionazarashi は準天頂衛星みちびきが送信する災危通報メッセージのデコーダーです。u-blox と Sony Spresense が出力するメッセージ形式に対応しています。災危通報(災害・危機管理通報サービス)とは、防災機関から発表される地震や津波発生時の災害情報などの危機管理情報を準天頂衛星みちびき経由で送信するサービスです。Installation$pipinstallazarashiPreparationデバイスに災危通報メッセージを出力させるための設定例です。u-blox M10S < UART > Raspberry Pi 4 + Ubuntu 22.04 + ubxtool (CLI)UARTを有効にするため、設定ファイルの末尾にenable_uart=1を追記します。$sudovi/boot/firmware/config.txt[all]...# Enable the UART portenable_uart=1再起動して、シリアルデバイスが認識されていることを確認します。$sudoreboot/dev/ttyS0の状態を確認しましょう。$stat/dev/ttyS0File:/dev/ttyS0Size:0Blocks:0IOBlock:4096characterspecialfile
Device:5h/5dInode:602Links:1Devicetype:4,40
Access:(0660/crw-rw----)Uid:(0/root)Gid:(20/dialout)...もし/dev/ttyS0が存在しない場合は dmsg コマンドで確認しましょう。ファイル名が異なるか UART ポートを有効化する設定が間違っているか、有効化に失敗していることが考えられます。$sudodmesg|grepserial[0.525432]bcm2835-aux-uartfe215040.serial:thereisnotvalidmapsforstatedefault[0.527303]fe215040.serial:ttyS0atMMIO0xfe215040(irq=21,base_baud=62500000)isa16550シリアルデバイスに sudo コマンドを使わずに読み書きしたいときは、ユーザをdialoutグループに追加します。$sudousermod-a-Gdialout$USER$logout# then re-login to the machineデータシートを参照して直接インストラクションを流し込むか、設定ツールをつかって SFRBX メッセージの出力を有効にしてください。設定ツール ubxtool は下記のようにインストールします。$sudoaptupdate
$sudoaptinstallgpsdgpsd-clientsSFRBX メッセージの出力に関連する設定コマンドの例です。$ubxtool-f/dev/ttyS0-s9600-zCFG-MSGOUT-UBX_RXM_SFRBX_UART1,1,1# sets 'enable'  to ram$ubxtool-f/dev/ttyS0-s9600-zCFG-MSGOUT-UBX_RXM_SFRBX_UART1,0,1# sets 'disable' to ram$ubxtool-f/dev/ttyS0-s9600-zCFG-MSGOUT-UBX_RXM_SFRBX_UART1,1,2# sets 'enable'  to bbr (battery-backed ram)$ubxtool-f/dev/ttyS0-s9600-zCFG-MSGOUT-UBX_RXM_SFRBX_UART1,0,2# sets 'disable' to bbr (battery-backed ram)$ubxtool-f/dev/ttyS0-s9600-gCFG-MSGOUT-UBX_RXM_SFRBX_UART1|grep-A3UBX-CFG-VALGET# gets the stateデバイスに通電してから災危通報メッセージを出力し始めるまでしばらく時間がかかります。u-blox F9P < USB > Windows + u-center (GUI)設定ツールu-centerをダウンロードし、インストールしてください。u-center で SFRBX メッセージを出力するように設定してください。下記は SFRBX メッセージを USB に出力するための参考設定手順です。Open u-center ->
  View -> Configuration View ->
    CFG (Configuration) -> Revert to default configuration -> Send
    MSG (Messages) -> Messages -> 02-13 RXM-SFRBX ->
      Check the "USB" box and type 1 in the "on" box -> Send
    NMEA (NMEA Protocol) -> NMEA Version -> Select 4.11 -> Send
    CFG (Configuration) -> Save current configuration -> Sendu-center で QZSS の L1S シグナル受信機能を有効にしてください。下記は GPS と QZSS のメッセージをすべて受信するための参考設定手順です。Open u-center ->
  View -> Generation 9 Configuration View -> GNSS Configuration ->
    Check All the "GPS" and "QZSS" boxes ->
  　　  Check the "RAM" and "Flash" boxes in the "Write to layer" ->
 　　　　   Send Configuration設定は永続化され、他の機器に接続し直しても災危通報メッセージを出力します。デバイスに通電してから災危通報メッセージを出力し始めるまでしばらく時間がかかります。Sony SpresenseQZSS 災危通報 (QZQSM) の NMEA センテンスを出力するように設定してください。CLIazarashi コマンドをつかうとプログラミングすることなく災危通報メッセージをデコードできます。$echo'$QZQSM,55,C6AF89A820000324000050400548C5E2C000000003DFF8001C00001185443FC*05'|azarashinmeaオプションは下記のとおりです。usage:azarashi[-h][-fINPUT][-s][-u][-v]{hex,nmea,ublox}azarashiCLI

positionalarguments:{hex,nmea,ublox}messagetypeoptions:-h,--helpshowthishelpmessageandexit-fINPUT,--inputINPUTinputdevice(default:stdin)-s,--sourceoutputthesourcemessages(default:False)-u,--uniquesupressduplicatemessages(default:False)-v,--verboseverbosemode(default:False)u-bloxstty コマンドでデバイスファイルをrawに設定し azarashi コマンドのメッセージタイプにubloxを指定します。デバイスファイルのパスは適宜変更してください。$stty-F/dev/ttyS0rawazarashi コマンドに ublox オプションを指定します。$azarashiublox-f/dev/ttyS0なお、デバイスファイルの読込権限が足りず sudo コマンドを使って python3 インタプリタを実行するとき azarashi モジュールも sudo で実行される python3 環境にインストールされている必要があることに注意してください。あるいは次のように実行しても動作は同じです。$sudocat/dev/ttyS0|azarashiubloxSony Spresenseazarashi コマンドに nmea オプションを指定します。$azarashinmea-f/dev/ttyUSB0Hexadecimalazarashi コマンドのメッセージタイプにhexを指定してください。hexはヘッダ、チェックサムを含まない16進数文字列のメッセージ形式です。$echoC6AF89A820000324000050400548C5E2C000000003DFF8001C00001185443FC|azarashihexAPIdecode()azarashi.decode(msg,msg_type='nmea')msg: メッセージを渡してください。メッセージは str 型または bytes 型です。msg_type: デフォルトはnmea、オプションとしてhexまたはubloxを指定できます。nmeaまたはhexを指定したときメッセージは str 型、ubloxを指定したときメッセージは bytes 型です。Exampleデコードして得られたレポートオブジェクトをstr()にわたすとヒューマンリーダブルな災害情報を返します。>>>importazarashi>>>msg='$QZQSM,55,C6AF89A820000324000050400548C5E2C000000003DFF8001C00001185443FC*05'>>>report=azarashi.decode(msg,'nmea')>>>str(report)'防災気象情報(緊急地震速報)(発表)(訓練/試験)\n*** これは訓練です ***\n緊急地震速報\n強い揺れに警戒してください。\n\n発表時刻: 3月10日10時0分\n\n震央地名: 日向灘\n地震発生時刻: 10日10時0分\n深さ: 10km\nマグニチュード: 7.2\n震度(下限): 震度6弱\n震度(上限): 〜程度以上\n島根、岡山、広島、山口、香川、愛媛、高知、福岡、佐賀、長崎、熊本、大分、宮崎、鹿児島、中国、四国、九州'つまりレポートオブジェクトをprint()にわたせば災害情報を出力します。>>>print(report)防災気象情報(緊急地震速報)(発表)(訓練/試験)
*** これは訓練です ***
緊急地震速報
強い揺れに警戒してください。

発表時刻: 3月10日10時0分

震央地名: 日向灘
地震発生時刻: 10日10時0分
深さ: 10km
マグニチュード: 7.2
震度(下限): 震度6弱
震度(上限): 〜程度以上
島根、岡山、広島、山口、香川、愛媛、高知、福岡、佐賀、長崎、熊本、大分、宮崎、鹿児島、中国、四国、九州レポートオブジェクトからパラメータを取得するにはget_params()メソッドを使います。>>>frompprintimportpprint>>>pprint(report.get_params()){'assumptive':False,'depth_of_hypocenter':'10km','depth_of_hypocenter_raw':10,'disaster_category':'緊急地震速報','disaster_category_en':'Earthquake Early Warning','disaster_category_no':1,'eew_forecast_regions':['島根','岡山','広島','山口','香川','愛媛','高知','福岡','佐賀','長崎','熊本','大分','宮崎','鹿児島','中国','四国','九州'],'eew_forecast_regions_raw':[37,38,39,40,42,43,44,45,46,47,48,49,50,51,66,67,68],'information_type':'発表','information_type_en':'Issue','information_type_no':0,'magnitude':'7.2','magnitude_raw':72,'message':b'\xc6\xaf\x89\xa8\x00\x03$\x00\x00P@\x05H\xc5\xe2\xc0\x00\x00\x00'b'\x03\xdf\xf8\x00\x1c\x00\x00\x11\x85D?\xc0','message_header':'$QZQSM','message_type':'DC Report (JMA)','nmea':'$QZQSM,55,C6AF89A820000324000050400548C5E2C000000003DFF8001C00001185443FC*05','notifications_on_disaster_prevention':['強い揺れに警戒してください。'],'notifications_on_disaster_prevention_raw':[201],'occurrence_time_of_earthquake':datetime.datetime(2023,3,10,1,0),'preamble':'C','raw':b'\xaf\x89\xa8\x00\x03$\x00\x00P@\x05H\xc5\xe2\xc0\x00\x00\x00\x03'b'\xdf\xf8\x00\x1c\x00\x00\x10','report_classification':'訓練/試験','report_classification_en':'Training/Test','report_classification_no':7,'report_time':datetime.datetime(2023,3,10,1,0),'satellite_id':55,'satellite_prn':183,'seismic_epicenter':'日向灘','seismic_epicenter_raw':791,'seismic_intensity_lower_limit':'震度6弱','seismic_intensity_lower_limit_raw':8,'seismic_intensity_upper_limit':'〜程度以上','seismic_intensity_upper_limit_raw':11,'sentence':'$QZQSM,55,C6AF89A820000324000050400548C5E2C000000003DFF8001C00001185443FC*05','timestamp':datetime.datetime(2023,6,29,9,22,2,203772),'version':1}重複して受信した同一情報のメッセージかどうかは等価演算子で判別できます。>>>msg2='$QZQSM,55,9AAF89A820000324000050400548C5E2C000000003DFF8001C0000123FB3EB0*03'>>>report2=azarashi.decode(msg2,'nmea')>>>report==report2Truedecode_stream()azarashi.decode_stream(stream,msg_type='nmea',callback=None,callback_args=(),callback_kwargs={},unique=False)stream: I/Oストリームを渡してください。デバイスファイルをopen()して渡すときは、事前に stty コマンドでubloxならrawモード、nmeaならデフォルト設定にしてください。pySerial つかうときは stty コマンドによる設定は不要です。msg_type: デフォルトはnmea、オプションとしてhexまたはubloxを指定できます。callback: メッセージをデコードしたあとに実行されるコールバック関数です。Noneの場合decode_stream()はメッセージをデコードするたびに結果を返します。コールバック関数が与えられた場合decode_stream()は例外が発生しない限り繰り返しメッセージをデコードし、そのたびにコールバック関数に結果を渡して実行します。下記はコールバック関数のインタフェースです。callback(report,*callback_args,**callback_kwargs)calback_args: コールバック関数に渡される引数です。callback_kwargs: コールバック関数に渡されるキーワード引数です。unique: 重複したメッセージを無視したいときはTrueを指定してください。Example指定したデバイスファイルを読み込み、デコードしたレポートオブジェクトをprint()に渡します。>>>importazarashi>>>f=open('/dev/ttyS0',mode='r')>>>azarashi.decode_stream(f,msg_type='ublox',callback=print)QzssDcrDecoderExceptionこの例外クラスは何らかの理由でデコードに失敗したときに送出されます。エラーメッセージを表示すると問題解決の一助となるでしょう。QzssDcrDecoderNotImplementedErrorNotImplementedErrorを継承した例外クラスです。実験的な配信など、デコーダが対応していないメッセージを受け取ったときに送出されます。配信がはじまると騒々しいのでデバッグ以外ではこの例外を握りつぶしたほうがよいかもしれません。ExamplesI/O Stream例外処理を加えた簡単なプログラムの例です。importazarashiimportsysdefexample():withopen('/dev/ttyS0',mode='r')asf:whileTrue:try:azarashi.decode_stream(f,msg_type='ublox',callback=print)exceptazarashi.QzssDcrDecoderExceptionase:print(f'# [{type(e).__name__}]{e}',file=sys.stderr)exceptazarashi.QzssDcrDecoderNotImplementedErrorase:print(f'# [{type(e).__name__}]{e}',file=sys.stderr)exceptEOFErrorase:print(f'{e}',file=sys.stderr)return0exceptExceptionase:print(f'# [{type(e).__name__}]{e}',file=sys.stderr)return1exit(example())pySerialpySerialでシリアルポートをopen()してdecode_stream()に渡すこともできます。この方法では stty コマンドによる設定は不要です。importazarashiimportsysimportserialimportpprintdefhandler(report):pprint.pprint(report.get_params())defexample():withserial.Serial('/dev/ttyS0',9600)asser:whileTrue:try:azarashi.decode_stream(ser,'ublox',handler,unique=True)exceptazarashi.QzssDcrDecoderExceptionase:print(f'# [{type(e).__name__}]{e}',file=sys.stderr)exceptazarashi.QzssDcrDecoderNotImplementedErrorase:print(f'# [{type(e).__name__}]{e}',file=sys.stderr)exceptEOFErrorase:print(f'{e}',file=sys.stderr)return0exceptExceptionase:print(f'# [{type(e).__name__}]{e}',file=sys.stderr)return1exit(example())NetworkGPS アンテナは屋外や窓際に設置する必要があるため、それが実際にデータを処理する装置の近くとは限りません。そこでデータを UDP パケットに載せて再送するスクリプトを書きました。IPv4/IPv6 両方に対応しています。簡単な実装なので、ソースを参考に改造するベースにもよいと思います。Transmitter送信側のスクリプトです。デフォルトでは IPv6 リンクローカルマルチキャストアドレスにパケットを送信します。宛先アドレスを指定したい場合は -d オプションを使用してください。$python3-mazarashi.network.transmitter-tublox-f/dev/ttyS0なお、デバイスファイルの読込権限が足りず sudo コマンドを使って python3 インタプリタを実行するとき azarashi モジュールも sudo で実行される python3 環境にインストールされている必要があることに注意してください。あるいは次のように実行しても動作は同じです。$sudocat/dev/ttyS0|python3-mazarashi.network.transmitter-tubloxオプションは下記のとおりです。usage: transmitter.py [-h] [-d DST_HOST] [-p DST_PORT] [-t {hex,nmea,ublox}] [-f INPUT] [-u]

azarashi network transmitter

options:
  -h, --help            show this help message and exit
  -d DST_HOST, --dst-host DST_HOST
                        destination host (default: ff02::1)
  -p DST_PORT, --dst-port DST_PORT
                        destination port (default: 2112)
  -t {hex,nmea,ublox}, --msg-type {hex,nmea,ublox}
                        message type (default: ublox)
  -f INPUT, --input INPUT
                        input device (default: stdin)
  -u, --unique          supress duplicate messages (default: False)Receiver受信側のスクリプトです。$python3-mazarashi.network.receiverオプションは下記のとおりです。usage: receiver.py [-h] [-b BIND_ADDR] [-p BIND_PORT] [-i BIND_IFACE] [-v]

azarashi network receiver

optional arguments:
  -h, --help            show this help message and exit
  -b BIND_ADDR, --bind-addr BIND_ADDR
                        address to bind (default: ::)
  -p BIND_PORT, --bind-port BIND_PORT
                        port to bind (default: 2112)
  -i BIND_IFACE, --bind-iface BIND_IFACE
                        iface to bind (default: any)
  -v, --verbose         verbose mode (default: False)NoteIS-QZSS-DCR-011 をサポートしています。TipsUnicodeDecodeError[UnicodeDecodeError] 'utf-8' codec can't decode byte 0xNN in position XX: ~GPSモジュールと接続するインタフェースのボーレートが一致せず、壊れたビット列をデコードしようとして失敗していることが考えられます。ボーレートは例えば次のような値です。9600, 19200, 38400, 57600, 115200設定方法はGPSモジュール、sttyまたはpySerialのマニュアルを参照してください。Encountered EOFCLI でストリームを受けていた azarashi は、書き込み側がクローズすると Encountered EOF と stderr に出力して終了します。これは正常な動作です。その直前までエラーなく動作していたと解釈してください。Feedbackイシュー報告、プルリクエスト、コメント等、なんでもよいのでフィードバックお待ちしています。星をもらうと開発が活発になります。