{"id":19222,"date":"2025-09-03T17:08:03","date_gmt":"2025-09-03T22:08:03","guid":{"rendered":"https:\/\/joefarris.com\/?page_id=19222"},"modified":"2025-09-03T17:08:25","modified_gmt":"2025-09-03T22:08:25","slug":"local-weather","status":"publish","type":"page","link":"https:\/\/joefarris.com\/index.php\/local-weather\/","title":{"rendered":"Local Weather"},"content":{"rendered":"        <div id=\"nrw-q7dDJ5MM\" class=\"nrw-wrap\" style=\"display:grid;gap:16px;\">\n            <div class=\"nrw-cards\" style=\"display:grid;grid-template-columns:repeat(4,minmax(150px,1fr));gap:12px;\">\n                <div class=\"nrw-card\"><strong>Temp (\u00b0C)<\/strong><div id=\"nrw-temp\">--<\/div><\/div>\n                <div class=\"nrw-card\"><strong>Humidity (%)<\/strong><div id=\"nrw-hum\">--<\/div><\/div>\n                <div class=\"nrw-card\"><strong>Pressure (hPa)<\/strong><div id=\"nrw-press\">--<\/div><\/div>\n                <div class=\"nrw-card\"><strong>Rainfall (mm)<\/strong><div id=\"nrw-rain\">--<\/div><\/div>\n            <\/div>\n\n            <canvas id=\"nrw-temp-chart\" height=\"120\"><\/canvas>\n            <canvas id=\"nrw-hum-chart\"  height=\"120\"><\/canvas>\n            <canvas id=\"nrw-press-chart\"height=\"120\"><\/canvas>\n            <canvas id=\"nrw-rain-chart\" height=\"120\"><\/canvas>\n\n            <div class=\"nrw-table-wrap\" style=\"overflow:auto;\">\n                <table id=\"nrw-table\" style=\"width:100%;border-collapse:collapse;\">\n                    <thead>\n                        <tr>\n                            <th style=\"text-align:left;border-bottom:1px solid #ccc;\">Date\/Time<\/th>\n                            <th style=\"text-align:right;border-bottom:1px solid #ccc;\">Rain (mm)<\/th>\n                            <th style=\"text-align:right;border-bottom:1px solid #ccc;\">Temp (\u00b0C)<\/th>\n                            <th style=\"text-align:right;border-bottom:1px solid #ccc;\">Humidity (%)<\/th>\n                            <th style=\"text-align:right;border-bottom:1px solid #ccc;\">Pressure (hPa)<\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody><\/tbody>\n                <\/table>\n            <\/div>\n        <\/div>\n\n        <script>\n        (function(){\n            const BASE   = \"https:\\\/\\\/joefarris.com\\\/index.php\\\/wp-json\\\/nr-weather\\\/v1\";\n            const el     = (id)=>document.getElementById(id);\n            const fmt    = (x)=> (x===null || x===undefined || isNaN(x)) ? '--' : Number(x).toFixed(1);\n\n            \/\/ Fetch history\n            async function getHistory(limit=48){\n                const r = await fetch(`${BASE}\/history?limit=${limit}`, {cache:'no-store'});\n                if(!r.ok) throw new Error('history fetch failed');\n                return r.json();\n            }\n            async function getLatest(){\n                const r = await fetch(`${BASE}\/latest`, {cache:'no-store'});\n                if(!r.ok) throw new Error('latest fetch failed');\n                return r.json();\n            }\n\n            \/\/ Charts\n            function makeLineChart(canvasId, label, labels, data, ymin=null, ymax=null){\n                const ctx = el(canvasId).getContext('2d');\n                return new Chart(ctx, {\n                    type: 'line',\n                    data: {\n                        labels,\n                        datasets: [{\n                            label,\n                            data,\n                            fill: false,\n                            tension: 0.2\n                        }]\n                    },\n                    options: {\n                        responsive: true,\n                        animation: false,\n                        scales: {\n                            y: { suggestedMin: ymin, suggestedMax: ymax },\n                            x: { ticks: { maxRotation: 0, autoSkip: true } }\n                        },\n                        plugins: { legend: { display: false } }\n                    }\n                });\n            }\n\n            function renderTable(rows){\n                const tbody = el('nrw-table').querySelector('tbody');\n                tbody.innerHTML = '';\n                rows.forEach(row=>{\n                    const tr = document.createElement('tr');\n                    const tdDt = document.createElement('td'); tdDt.textContent = row.recorded_at;\n                    const tdR  = document.createElement('td'); tdR.style.textAlign='right'; tdR.textContent = fmt(row.rainfall_mm);\n                    const tdT  = document.createElement('td'); tdT.style.textAlign='right'; tdT.textContent = fmt(row.temperature);\n                    const tdH  = document.createElement('td'); tdH.style.textAlign='right'; tdH.textContent = fmt(row.humidity);\n                    const tdP  = document.createElement('td'); tdP.style.textAlign='right'; tdP.textContent = fmt(row.pressure);\n                    tr.append(tdDt, tdR, tdT, tdH, tdP);\n                    tbody.appendChild(tr);\n                });\n            }\n\n            let charts = {};\n            async function refresh(){\n                try{\n                    const [latest, history] = await Promise.all([getLatest(), getHistory(72)]);\n                    \/\/ Cards\n                    el('nrw-temp').textContent  = fmt(latest?.temperature);\n                    el('nrw-hum').textContent   = fmt(latest?.humidity);\n                    el('nrw-press').textContent = fmt(latest?.pressure);\n                    el('nrw-rain').textContent  = fmt(latest?.rainfall_mm);\n\n                    \/\/ Charts (reverse chronological \u2192 chronological)\n                    const rows = [...history].reverse();\n                    const labels = rows.map(r => r.recorded_at.replace(' ', '\\n'));\n                    const temps  = rows.map(r => r.temperature);\n                    const hums   = rows.map(r => r.humidity);\n                    const press  = rows.map(r => r.pressure);\n                    const rain   = rows.map(r => r.rainfall_mm);\n\n                    if (!charts.temp)  charts.temp  = makeLineChart('nrw-temp-chart',  'Temperature (\u00b0C)', labels, temps, 0, 40);\n                    else { charts.temp.data.labels = labels; charts.temp.data.datasets[0].data = temps; charts.temp.update(); }\n\n                    if (!charts.hum)   charts.hum   = makeLineChart('nrw-hum-chart',   'Humidity (%)',     labels, hums, 0, 100);\n                    else { charts.hum.data.labels = labels; charts.hum.data.datasets[0].data = hums; charts.hum.update(); }\n\n                    if (!charts.press) charts.press = makeLineChart('nrw-press-chart', 'Pressure (hPa)',   labels, press, 950, 1050);\n                    else { charts.press.data.labels = labels; charts.press.data.datasets[0].data = press; charts.press.update(); }\n\n                    if (!charts.rain)  charts.rain  = makeLineChart('nrw-rain-chart',  'Rainfall (mm)',    labels, rain, 0, undefined);\n                    else { charts.rain.data.labels = labels; charts.rain.data.datasets[0].data = rain; charts.rain.update(); }\n\n                    renderTable(history);\n                } catch(e) { console.error(e); }\n            }\n\n            refresh();\n            setInterval(refresh, 60*1000); \/\/ refresh each minute\n        })();\n        <\/script>\n        \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-19222","page","type-page","status-publish","hentry","description-off"],"_links":{"self":[{"href":"https:\/\/joefarris.com\/index.php\/wp-json\/wp\/v2\/pages\/19222","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/joefarris.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/joefarris.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/joefarris.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/joefarris.com\/index.php\/wp-json\/wp\/v2\/comments?post=19222"}],"version-history":[{"count":2,"href":"https:\/\/joefarris.com\/index.php\/wp-json\/wp\/v2\/pages\/19222\/revisions"}],"predecessor-version":[{"id":19224,"href":"https:\/\/joefarris.com\/index.php\/wp-json\/wp\/v2\/pages\/19222\/revisions\/19224"}],"wp:attachment":[{"href":"https:\/\/joefarris.com\/index.php\/wp-json\/wp\/v2\/media?parent=19222"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}