1295 文字
6 分
東の果てが晴れているか確認するマップを作った
犬吠さん参りをした
月齢が浅く、晴れる見込みがあったため、犬吠埼に行ってきた。
結局天気予報は外れ、寒い中曇り空を撮影する羽目になった。

こんな感じで、時折晴れていたりもしてたが、だいたいこんな空模様だった。
(地面が赤いのは近くの車のランプのせい)
Home Assistantとひまわり衛星でマップを作成
天気は分からなかったが、雲がどこにいるか把握する余地はあった。
犬吠埼の日の出は、得てして遠くの雲に阻まれる。3回行ったが毎度雲が邪魔して水平線からは出てこなかった。
絶望はいつも仄かな希望とともに現れ、その希望を潰してくる。
ダメージを減らすためにも、最初から希望は無いものとして覚悟しておきたい。
GPTに聞きつつ調べたら、だいたい70kmの距離までに低層雲がなければ太陽は水平線から現れるらしい。
そして、日本には「ひまわり」という衛星があり、天気を見張ってくれている。
Home AssistantでLeafletの地図からスマホの位置情報を拾って移動ヒートマップを作成したことがあるので、これは応用可能だ。
GPTに依頼したらコードを生成してくれた。
帰宅して軽く9時間の仮眠を取ったあと、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: '© 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 RGB(ngt) 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>犬吠埼周辺の雲を可視化
犬吠埼を中心として見える雲の情報を把握・予測するためにマップを作った。

10km,30km,70kmの円周を作って「この範囲に雲がなければOK!」ということが分かる。
これで犬吠にいなくても撮影に適しているかが分かる。犬吠にいなかったら撮影もできないが。
おまけ
全くの曇天というわけでもなく、時折晴れたりしていた。寒さに耐えたので、気骨が養われた。



