気象庁のアメダス情報を取得し、 PHP で1地点だけ情報を抽出する

## 気象庁のアメダスページは JSON ファイルを元に作られている
気象庁のサイトから情報を抽出するシリーズ、今度はアメダス編である。
気象庁サイトのアメダス情報は、下記のような地図形式と、地点を選択した時に出る表形式からなっている。

https://www.jma.go.jp/bosai/map.html#5/&elem=temp&contents=amedas&interval=10

アメダス値に関しては以下のような JSON ファイルが読み込まれる
- 地図
    - YYYYMMDDhh0000.json (1時間図)
    - YYYYMMDDhhm000.json (10分図)
- 都道府県表
    - YYYYMMDDhh0000.json
    - YYYYMMDDhhm000.json
- 地点表
    - YYYYMMDD_hh.json (1ファイルで3時間分、内容は当該地点のみ)

このうち、地図形式や都道府県表で用いられる10分ごと・1時間ごとの JSON ファイルには全地点の情報が含まれているため、任意の地点について地点コードを手がかりに抽出することが可能である。

ちなみに、1時間毎の観測しか行われない積雪・降雪量と自動観測天気は、正時以外の10分毎の JSON ファイルには含まれない。都道府県表で必ず2つのJSONファイルが読み込まれるのはそのためである。

## いつアメダスデータの JSON ファイルがアップロードされるのか
ファイル名は日時で決め打ちできるが、問題はこのファイルがいつアップロードされるかである。
何度か確認したところ、ファイル名の日時の6分後から遅くても7分後に達しない時間にアップされるようである。
そこで、現在時刻から7分巻き戻して10分以下の端数を切り捨てる形でファイル名を作ることにする。


## 作ってみた
```php: jma_amedas_json.php
<?php
error_reporting(0);
$point = $_GET['point'];
if ($point == "") {
    $point = "44132";
}
date_default_timezone_set('Asia/Tokyo');
$gettime = time()-420;
$urlnum = substr(date("YmdHi", $gettime),0,11) . "000";
$url = "https://www.jma.go.jp/bosai/amedas/data/map/". $urlnum . ".json";
$amedas_json = file_get_contents($url);
$amedas_array = json_decode($amedas_json, true);
$amedas = $amedas_array[$point];
$temp = sprintf('%.1f',$amedas["temp"]["0"]);
$prec1h = sprintf('%.1f',$amedas["precipitation1h"]["0"]);
$wind = sprintf('%.1f',$amedas["wind"]["0"]);
echo '{"datetime":"' . $urlnum . '", ';
echo '"point":"' . $point . '", ';
echo '"temp":"' . $temp . '", ';
echo '"prec1h":"' . $prec1h . '", ';
echo '"wind":"' . $wind . '"}';
?>
```
Awtrix で現在気温表示と、悪天時の降水・風速を表示させる目的で JSON ファイルを作成するので、要素は絞った。

URLクエリパラメータで `?point=地点コード` と指定するとその地点のアメダスデータを取得できるようにした。
地点コードを指定せず実行した時は、エラー表示を抑制した上で、東京の地点コードを入れるようにしている。

`time` 関数で取得できる現在時刻は Unix エポックからの秒数であるため、7分巻き戻したい場合は420秒引けばよい。
あとは `date` 関数で `YYYYMMDDhhmm` 形式にした後、後ろ1桁を捨てて 000 （1桁分+秒）をフィルした。

元となる JSON ファイルは数値に関してはダブルクォーテーションが付いていない形であるため、 PHP が JSON ファイルをパースする時点で小数第1位が 0 の値は自動的に整数変換されてしまう。
変数から取り出す際、小数第1位までの値を取るものは `sprintf` で小数第1位までにフォーマットし直し、小数第1位の 0 も表示できるようにする。
さらに、この JSON を再利用することを考え、出力時には値を全てダブルクォーテーションで括り、文字列として認識させることにする。

実行すると、このような JSON 形式の出力がなされる。
```json: 
{"datetime":"20241223193000", "point":"44132", "temp":"7.3", "prec1h":"0.0", "wind":"1.7"}
```

## Node-Red 経由で Awtrix に表示させよう
地点を抽出した JSON データは Node-Red (JavaScript) で容易に扱うことができる。
http request は URL で地点コードを指定し、出力形式は JSON。
```moonscript:
http://サーバー名:ポート/php/jma_amedas_json.php?point=48156
```

function は気温だけ抽出すればよいので以下のようなコードでよい。
```javascript: 
var amedas_array = msg.payload;
var temp = amedas_array.temp + "C";
msg.payload = {"text": temp, "icon": "temperature"};
return msg;
```
最後に mqtt out で適切なトピック名を指定すれば Awtrix に表示される。

icon は温度計のアイコンを使ってもよいし、複数地点を表示させたければ市区町村章やマスコットを8×8のアイコンにして使ってもよいかもしれない（ドット数が少な過ぎて至難の技である）。
![php_amedas1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943774/9956ee1d-4a92-c4d5-5e3a-b65171dd8752.png)


## Advent Calendar 完走
CASIO Graph Math+ の注文をきっかけに Qiita と [ひとりアドベント](https://qiita.com/advent-calendar/2024/hary_calc_py) を始めたものの、その後購入した MeePet（Android としても使える安価なテレビ会議専用機）や TC001（スマートピクセルクロック）のネタがメインに。その分扱う範囲が Python から PHP、 RSS、 MQTT と広がり、ネタには不自由せず25日間投稿することができた。
ネットのリソースに若干手を加えたネタがほとんどでお世辞にもクォリティのよい記事というわけではないが、やろうと思えば Advent Calendar の完走はできるということを示せたと思う。

Advent Calendar 企画に感謝します。