+
☀️
UV Index
{current.uv_index != null ? Math.round(current.uv_index) : '--'}
diff --git a/src/components/WeatherDetail.svelte b/src/components/WeatherDetail.svelte
index d243f34..8d5ceb0 100644
--- a/src/components/WeatherDetail.svelte
+++ b/src/components/WeatherDetail.svelte
@@ -9,6 +9,8 @@
const unit = $derived(app.settings.units === 'imperial' ? '°F' : '°C')
const windUnit = $derived(app.settings.units === 'imperial' ? 'mph' : 'km/h')
+ const fbPressure = $derived(!!data?._fallback?.pressure)
+ const fbUv = $derived(!!data?._fallback?.uv)
function windCompass(deg) {
if (deg == null) return '--'
@@ -95,7 +97,7 @@
Pressure
- {Math.round(current.pressure_msl || 0)} hPa
+ {Math.round(current.pressure_msl || 0)} hPa
Feels Like
@@ -117,7 +119,7 @@
UV Index
-
+
{current.uv_index != null ? Math.round(current.uv_index) : '--'}
{#if current.uv_index != null}
{getUVLevel(current.uv_index)}
@@ -134,7 +136,7 @@
Max UV Today
- {daily?.uv_index_max?.[0] != null ? Math.round(daily.uv_index_max[0]) : '--'}
+ {daily?.uv_index_max?.[0] != null ? Math.round(daily.uv_index_max[0]) : '--'}
diff --git a/src/lib/api/nws.js b/src/lib/api/nws.js
index 5b76598..4828c66 100644
--- a/src/lib/api/nws.js
+++ b/src/lib/api/nws.js
@@ -252,3 +252,29 @@ export async function fetchForecastNWS(lat, lon, units = 'imperial') {
return normalizeNWS({ points, forecast, hourly, grid, timeZone: tz, units })
}
+
+/**
+ * Backfill fields that NWS does not provide (pressure, UV index) from an
+ * Open-Meteo response, tagging them so the UI can show a tooltip that the
+ * value came from the non-selected source.
+ */
+export function mergeFallbackData(nwsData, omData) {
+ const fallback = {}
+ const cur = nwsData.current || {}
+ const omCur = omData?.current || {}
+ if (omCur.pressure_msl != null) {
+ cur.pressure_msl = omCur.pressure_msl
+ fallback.pressure = true
+ }
+ if (omCur.uv_index != null) {
+ cur.uv_index = omCur.uv_index
+ fallback.uv = true
+ }
+ const omDaily = omData?.daily || {}
+ if (omDaily.uv_index_max?.length && nwsData.daily) {
+ nwsData.daily.uv_index_max = omDaily.uv_index_max
+ fallback.uv = true
+ }
+ if (Object.keys(fallback).length) nwsData._fallback = fallback
+ return nwsData
+}
diff --git a/src/lib/stores/app.svelte.js b/src/lib/stores/app.svelte.js
index 9ff75b9..7f9eda5 100644
--- a/src/lib/stores/app.svelte.js
+++ b/src/lib/stores/app.svelte.js
@@ -4,7 +4,7 @@
import { getLocations, loadSettings } from '../storage/db.js'
import { fetchForecast } from '../api/weather.js'
-import { fetchForecastNWS } from '../api/nws.js'
+import { fetchForecastNWS, mergeFallbackData } from '../api/nws.js'
export class AppStore {
// Location state
@@ -116,6 +116,14 @@ export class AppStore {
if (source === 'nws') {
try {
data = await fetchForecastNWS(location.lat, location.lon, units)
+ // NWS omits pressure + UV index — backfill those from Open-Meteo and
+ // flag them so the UI can tooltip that they came from the other source.
+ try {
+ const om = await fetchForecast(location.lat, location.lon, units)
+ data = mergeFallbackData(data, om)
+ } catch (omErr) {
+ console.warn('Open-Meteo fields unavailable:', omErr.message)
+ }
} catch (nwsErr) {
// NWS is US-only and can be unavailable — fall back to Open-Meteo
// so the app keeps working rather than breaking.
diff --git a/tests/nws.test.js b/tests/nws.test.js
index 1f11a12..dcf5e43 100644
--- a/tests/nws.test.js
+++ b/tests/nws.test.js
@@ -8,6 +8,7 @@ import {
dateKey,
localTimeString,
normalizeNWS,
+ mergeFallbackData,
} from '../src/lib/api/nws.js'
const FIX = (name) => JSON.parse(readFileSync(path.join('tests/fixtures/nws', name), 'utf8'))
@@ -103,3 +104,26 @@ describe('normalizeNWS (recorded live fixture for Rogers County, OK)', () => {
expect(m.current.wind_speed_10m).toBeCloseTo(10 * 1.609344, 1)
})
})
+
+describe('mergeFallbackData', () => {
+ it('backfills pressure + UV from Open-Meteo and tags them (non-selected source)', () => {
+ const nws = {
+ _source: 'nws',
+ current: { temperature_2m: 103, pressure_msl: null, uv_index: null },
+ daily: { time: ['2026-08-16'], uv_index_max: [] },
+ }
+ const om = { current: { pressure_msl: 1011.2, uv_index: 7.4 }, daily: { uv_index_max: [7.2, 6, 5] } }
+ const r = mergeFallbackData(nws, om)
+ expect(r.current.pressure_msl).toBe(1011.2)
+ expect(r.current.uv_index).toBe(7.4)
+ expect(r.daily.uv_index_max).toEqual([7.2, 6, 5])
+ expect(r._fallback).toMatchObject({ pressure: true, uv: true })
+ })
+
+ it('does not tag when Open-Meteo lacks the fields', () => {
+ const nws = { current: { pressure_msl: null, uv_index: null }, daily: {} }
+ const om = { current: { pressure_msl: null, uv_index: null }, daily: {} }
+ const r = mergeFallbackData(nws, om)
+ expect(r._fallback).toBeUndefined()
+ })
+})