[2022-08-28] COCOA通知が来ました(2022-08-24に「合計51分間の接触」)。その時点のデータまで追記してあります(exposure_data.json も)。
COCOA 2.0.0 になって、MatchCount がログに記録されないようになりました。
COCOA 2.0.1 になって、COCOA アプリの「陽性登録者との接触結果を確認」→「情報を保存」で exposure_data.json という詳細ログが保存できるようになりました。これを見れば接触日などがわかります。私の iPhone のデータ例を置いておきます。中を見るための Python プログラムの一例です(同様なことをするためのサイト COCOAログチェッカー2.0 (β) や COCOAログ.jp ができました):
import json import pandas as pd with open("exposure_data.json") as f: exposure = json.load(f) print("Date Infectiousness TypicalAttenuationDb MinAttenuationDb SecondsSinceLastScan") for x in exposure["exposure_windows"]: t = pd.Timestamp(x['DateMillisSinceEpoch'], unit='ms') print(str(t)[:10], x["Infectiousness"], end="") for y in x["ScanInstances"]: print(" ", y["TypicalAttenuationDb"], y["MinAttenuationDb"], y["SecondsSinceLastScan"], end="") print()
出力:
2022-03-25 2 97 92 120 2022-03-31 2 91 91 60 2022-04-01 2 93 93 60 2022-04-14 2 93 88 60 2022-07-04 2 91 87 60 2022-07-04 2 91 91 60 2022-07-18 2 91 84 120 90 90 60 2022-07-19 2 89 89 60 2022-07-22 2 91 91 60 2022-07-23 2 87 87 60 84 78 120 2022-07-28 2 94 94 120 95 95 60 2022-07-29 2 89 89 60 2022-08-01 2 88 80 60 2022-08-04 2 100 100 60 2022-08-05 2 98 98 60 90 89 60 98 98 60 2022-08-13 2 89 89 60 2022-08-19 2 83 83 60 2022-08-19 2 80 69 120 85 79 60 2022-08-19 2 78 76 60 2022-08-19 2 86 86 60 2022-08-19 2 87 87 60 2022-08-19 2 91 91 60 2022-08-19 2 88 82 60 2022-08-20 2 96 96 60 2022-08-20 2 90 89 60 2022-08-21 2 101 101 60 2022-08-21 2 98 98 60 2022-08-21 2 86 86 60 2022-08-21 2 87 87 60 2022-08-21 2 89 87 60 87 83 120 2022-08-22 2 86 84 60 2022-08-22 2 94 94 60 2022-08-22 2 90 90 60 2022-08-22 2 97 97 60 2022-08-23 2 85 85 60 2022-08-23 2 87 82 120 97 97 60 2022-08-24 2 53 51 180 55 49 120 51 46 120 55 54 180 58 58 60 58 56 180 58 50 240 68 64 180 57 56 60 63 56 120 63 63 60 58 55 180 2022-08-24 2 85 81 180 84 76 120 93 89 180 96 92 180 95 95 60 95 94 120 93 89 60 94 94 60 93 91 180 93 87 240 96 92 120 2022-08-24 2 91 90 120 96 93 120 93 92 180 96 96 60 93 93 60 93 93 180 2022-08-24 2 88 86 60 2022-08-24 2 59 58 180 62 59 240 64 64 60 59 55 300 56 56 60 66 66 60 61 59 120 58 58 60 2022-08-24 2 80 75 120 74 71 60 2022-08-24 2 82 82 60 2022-08-24 2 92 92 60 2022-08-24 2 76 69 120 83 83 60 2022-08-24 2 93 93 60 2022-08-26 2 95 95 60 2022-09-05 2 85 85 60
表示される日付の9:00から丸一日の間に接触があったことがわかります。日付以外の項目の意味は Google のドキュメント に説明されています(いまいちよくわからない説明ですが)。鈴木健治さんのCOCOAの接触時間が長い理由と、COCOAログチェッカー件数の意味がたいへんわかりやすい解説です。
一つの exposure_windows の要素はたかだか30分で、これ以上の接触は2回と数えられます。ですから、上の例の 2022-07-04 は、2人に会ったか、1人に2回会ったか、1人に30分を超えて会ったか、ということのようです。TypicalAttenuationDb と MinAttenuationDb はそれぞれ BLE(Bluetooth Low Energy)電界強度の dB(デシベル)値の平均値・最小値です。dB 値が小さいほど電界強度が強いことになります。野上大介さんの解説によれば 5m 離れていれば 65〜75dB 程度のようです。SecondsSinceLastScan は秒数を 60 の倍数に丸めたものです。
ちなみに、iPhone の「設定」→「接触通知」→「使用中」→「接触チェックの記録」に出る「一致したキーの数」は次のような不思議な変化をします:
このあとずっと 0 でしたが、2022-07-08 に 1 に転じました。変化のあったところだけを書き出すと次のようになります:
2022-03-30 15:38,1 2022-04-03 17:20,2 2022-04-07 17:29,3 2022-04-16 15:53,1 2022-04-17 00:28,0 2022-04-18 16:08,1 2022-05-14 15:54,0 2022-07-08 14:37,1 2022-07-21 02:54,0 2022-07-23 00:20,1 2022-07-23 12:58,2 2022-07-23 21:00,3 2022-07-25 16:31,4 2022-08-04 02:53,5 2022-08-05 22:00,4 2022-08-06 17:43,5 2022-08-07 10:50,4 2022-08-08 21:21,5 2022-08-13 04:22,4 2022-08-14 04:23,3 2022-08-19 19:57,2 2022-08-20 23:59,1 2022-08-22 04:00,2 2022-08-22 19:56,4 2022-08-22 23:57,5 2022-08-23 15:58,6 2022-08-23 19:57,7 2022-08-23 23:58,9 2022-08-24 13:00,10 2022-08-24 17:02,11 2022-08-25 00:00,13 2022-08-25 04:01,14 2022-08-26 03:54,15 2022-08-26 22:32,19 2022-08-27 03:30,20 2022-08-27 13:24,21 2022-08-27 19:26,23 2022-08-28 00:23,25 2022-08-28 05:20,26
どうやらこの「一致したキーの数」は積算値で、何かのタイミングでリセットされるようですが、詳細はわかりません。おそらく「一致したキーの数」が変化したタイミングで exposure_data.json も書き変わるのだと思います。
以下は古い記述です。
iPhoneにCOCOAをインストールしている。接触チェックの記録は,「設定」→「接触通知」→「接触のログ記録の状況」→「接触チェックの記録」→「接触チェックの記録を書き出す」でAirDropなどの手段で書き出すことができる。書き出されるのは ExposureChecks-YYYY-MM-DD.json のようなJSONファイルである。これを読んでみよう。
ExportVersion
という項目があり,古いものは1,新しいものは2になっている。次のようにすれば接触情報(MatchCount
が0以外)および毎日のキー数を表示できる:
#! /usr/bin/env python3 import sys import json def show(d): print() for k in ["Hash", "MatchCount", "Timestamp"]: print(k, d[k]) keycount = {} for arg in sys.argv[1:]: with open(arg) as f: d = json.load(f) print(arg, "ExportVersion:", d["ExportVersion"]) if d["ExportVersion"] == 1: for i in d["ExposureChecks"]: keycount[i["Timestamp"]] = keycount.get(i["Timestamp"], 0) + i["RandomIDCount"] if i["MatchCount"] != 0: show(i) elif d["ExportVersion"] == 2: for i in d["ExposureChecks"]: for j in i["Files"]: keycount[i["Timestamp"]] = keycount.get(i["Timestamp"], 0) + j["KeyCount"] if "MatchCount" in j and j["MatchCount"] != 0: # ENv2ではMatchCountはない show(j) else: print(arg, "Unknown ExportVersion:", d["ExportVersion"]) print() for k in sorted(keycount): print(k, keycount[k])
出力例:
ExposureChecks-2020-09-12.json ExportVersion: 2 Hash 6CBAA717FA2D584F2E8A77731C4B7D5294ED4B7E899EC3D4E54598BDCDE0400B MatchCount 1 Timestamp 2020-09-12 01:15:24 +0900 2020-08-29 00:38:00 +0900 408 2020-08-30 00:41:07 +0900 178 2020-08-31 01:08:33 +0900 162 2020-09-01 00:48:51 +0900 422 2020-09-02 01:46:07 +0900 207 2020-09-03 03:01:08 +0900 328 2020-09-04 03:20:12 +0900 289 2020-09-05 03:50:32 +0900 315 2020-09-06 00:13:21 +0900 121 2020-09-07 00:22:34 +0900 58 2020-09-08 00:45:24 +0900 276 2020-09-09 00:54:57 +0900 209 2020-09-10 01:04:33 +0900 236 2020-09-11 03:08:06 +0900 481 2020-09-12 01:15:24 +0900 412
MatchCount が 0 でないハッシュ値を 鈴木健治さんの接触日シート別冊 または https://cacaotest.sakura.ne.jp で検索すれば接触日がわかる。同じことが COCOAログチェッカー でできる。
[COCOA 2] COCOA 2.0.0 beta の段階で ExposureChecks-*.json から MatchCount の欄が消えた。これは ENv2 を採用したためである。
COCOAの動作ログについては COCOA 突如として初期化される問題(UserDataが壊れている) #16 に詳しい。
COCOAアプリを立ち上げて,左上の三本線メニュー→「アプリに関するお問い合わせ」→「動作情報を送信」→「動作情報を確認する」→「保存完了OK」,いったんCOCOAを閉じて「ファイル」アプリを立ち上げ,「接触確認アプリ」フォルダを開き,cocoa_log_*.zip というファイルを長押しし,「共有」でAirDropなどでパソコンに送る(zipファイルを長押ししないでタップするとiPhoneの中で展開される)。
このzipファイルを展開すると2週間分のcsvファイルが出てくる。中はCOCOAの動作ログである。
次のようなスクリプトでエラー行だけ表示することができる:
#! /usr/bin/env python3 import re import sys from zipfile import ZipFile for arg in sys.argv[1:]: with ZipFile(arg) as z: for x in z.namelist(): with z.open(x) as f: for r in f: line = r.decode('utf-8') if re.search('^.*?,"Error",', line): print(line)
出力例:
"2021/02/01 13:09:59","Error","Fail to download files, ...(後略)... "2021/02/01 17:12:55","Error","Failed to get terms update info., ...(後略)... "2021/01/31 21:14:08","Error","Failed to check version., ...(後略)...