1295 文字
6 分
東の果てが晴れているか確認するマップを作った

犬吠さん参りをした#

月齢が浅く、晴れる見込みがあったため、犬吠埼に行ってきた。

結局天気予報は外れ、寒い中曇り空を撮影する羽目になった。

曇り空

こんな感じで、時折晴れていたりもしてたが、だいたいこんな空模様だった。

(地面が赤いのは近くの車のランプのせい)

Home Assistantとひまわり衛星でマップを作成#

天気は分からなかったが、雲がどこにいるか把握する余地はあった。

犬吠埼の日の出は、得てして遠くの雲に阻まれる。3回行ったが毎度雲が邪魔して水平線からは出てこなかった。

絶望はいつも仄かな希望とともに現れ、その希望を潰してくる。

ダメージを減らすためにも、最初から希望は無いものとして覚悟しておきたい。

GPTに聞きつつ調べたら、だいたい70kmの距離までに低層雲がなければ太陽は水平線から現れるらしい。

そして、日本には「ひまわり」という衛星があり、天気を見張ってくれている。

Home AssistantでLeafletの地図からスマホの位置情報を拾って移動ヒートマップを作成したことがあるので、これは応用可能だ。

GPTに依頼したらコードを生成してくれた。

帰宅して軽く9時間の仮眠を取ったあと、Home Assistantを弄った。

技術的な課題:緯度のズレ補正#

僅かに緯度にズレがあった。

Home Assistantで作成した犬吠埼周辺の雲マップ - 緯度補正前のズレが見られる画面

Claude Codeと格闘して補正を行わせた。

何度か格闘の末、多少の誤差はあれど問題なくなった。1.7°の補正が必要とわかった。

最終的なコード実装#

結局こんなコードになった。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>Himawari Fog/Low Cloud - Inubosaki</title>
  <!-- Leaflet -->
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
  <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
  <style>
    html, body, #map { height: 100%; margin: 0; }
    .badge {
      position: absolute; z-index: 9999; left: 8px; bottom: 8px;
      background: rgba(0,0,0,.55); color: #fff; padding: 6px 8px;
      font: 12px/1.2 system-ui, -apple-system, "Segoe UI", sans-serif;
      border-radius: 8px;
    }
  </style>
</head>
<body>
<div id="map"></div>
<div class="badge" id="status">loading…</div>
<script>
  // 犬吠埼(概略)
  const INUBOU = { lat: 35.7056, lon: 140.8699 };
  // 150×150km程度の視野(ざっくり換算)
  const VIEW_BOUNDS = L.latLngBounds(
    [35.03, 140.03],  // SW
    [36.38, 141.71]   // NE
  );
  // 気象庁MSC「Japan」画像の座標
  // 元座標: (115E,22N)-(155E,48N)、緯度のみ補正(1.7°)
  const JPN_IMG_BOUNDS = L.latLngBounds(
    [21.2, 115.0], // SW (19.5 + 1.7)
    [47.2, 155.0]  // NE (45.5 + 1.7)
  );
  // ベース地図
  const map = L.map('map', { preferCanvas: true });
  map.fitBounds(VIEW_BOUNDS);
  L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 19,
    attribution: '&copy; OpenStreetMap contributors'
  }).addTo(map);
  let overlay = null;
  // UTC時刻を「データが出揃っている側」に寄せて 10分単位に丸める
  function latestSlotUTC(offsetMinutes = 20) {
    const now = new Date();
    const t = new Date(now.getTime() - offsetMinutes * 60 * 1000); // 少し遅らせる
    const hh = String(t.getUTCHours()).padStart(2, '0');
    const mm = t.getUTCMinutes();
    const mm10 = String(Math.floor(mm / 10) * 10).padStart(2, '0');
    return `${hh}${mm10}`; // "HHMM"
  }
  // 昼夜で切り替え(簡易):日本時間 6-18 を昼、それ以外を夜
  function pickProductCode() {
    const jst = new Date(Date.now() + 9 * 60 * 60 * 1000);
    const h = jst.getUTCHours();
    // 昼:Day Snow-Fog RGB(ファイル側は dsl が一般的に見えます)
    // 夜:Night Microphysics RGBngt
    return (h >= 6 && h < 18) ? 'dsl' : 'ngt';
  }
  function buildImageURL() {
    const slot = latestSlotUTC(20);
    const code = pickProductCode();
    // 例: https://www.data.jma.go.jp/mscweb/data/himawari/img/jpn/jpn_ngt_0150.jpg
    return { slot, code, url: `https://www.data.jma.go.jp/mscweb/data/himawari/img/jpn/jpn_${code}_${slot}.jpg` };
  }
  function refreshOverlay() {
    const { slot, code, url } = buildImageURL();
    // 差し替え(キャッシュ回避にクエリを付与)
    const urlNoCache = `${url}?t=${Date.now()}`;
    if (overlay) map.removeLayer(overlay);
    overlay = L.imageOverlay(urlNoCache, JPN_IMG_BOUNDS, { opacity: 0.60, interactive: false });
    overlay.addTo(map);
    document.getElementById('status').textContent =
      `overlay: jpn_${code}_${slot}.jpg (UTC) / opacity 0.60`;
  }
  refreshOverlay();
  // 5分ごとに更新(衛星画像は10分刻みなのでこれで十分追従)
  setInterval(refreshOverlay, 5 * 60 * 1000);
</script>
</body>
</html>

犬吠埼周辺の雲を可視化#

犬吠埼を中心として見える雲の情報を把握・予測するためにマップを作った。

Home Assistantで作成した犬吠埼周辺の雲マップ - 10km/30km/70kmの円周表示

10km,30km,70kmの円周を作って「この範囲に雲がなければOK!」ということが分かる。

これで犬吠にいなくても撮影に適しているかが分かる。犬吠にいなかったら撮影もできないが。

おまけ#

全くの曇天というわけでもなく、時折晴れたりしていた。寒さに耐えたので、気骨が養われた。

犬吠空写真1

犬吠空写真2

犬吠空写真3

犬吠空写真4