3.3
Added pets profile
This commit is contained in:
+60
-3
@@ -2,7 +2,8 @@
|
||||
// compute.js - Build the per-hour display rows from the raw API data.
|
||||
//
|
||||
// Pure-ish function: feed in (forecast, airQuality, location, vehicleType,
|
||||
// vehicleVent, vehicleSpeed, buildingType) and get back { hourlyRows, days, utcOffsetMs }.
|
||||
// vehicleVent, vehicleSpeed, buildingType, furColor) and get back
|
||||
// { hourlyRows, days, utcOffsetMs }.
|
||||
//
|
||||
// Open-Meteo with timezone=auto returns local wall-clock strings like
|
||||
// "2026-05-13T14:00" - no Z suffix. Two forms are used in each row:
|
||||
@@ -14,11 +15,12 @@ import {
|
||||
vaporPressureHpa, solarElevationDeg, calcTmrt, utciApprox,
|
||||
calcConcreteTempPass, calcVehicleInteriorTemp,
|
||||
calcIndoorTempPass, calcManagedIndoorTempPass, calcShadeAirTemp,
|
||||
calcFurSurfaceTempPass,
|
||||
} from './physics.js';
|
||||
import { windCompass8, uvSplit, cloudCategory, precipPenalty, sunburnMinutes, burnLabel } from './utils.js';
|
||||
import { windCompass8, uvSplit, cloudCategory, precipPenalty, sunburnMinutes, burnLabel, FUR_COLORS } from './utils.js';
|
||||
import { UTCI_ENVIRONMENTS, CROP_CALENDAR } from './config.js';
|
||||
|
||||
export function buildHourlyRows({ forecast, airQuality, location, vehicleType, vehicleVent, vehicleSpeed, buildingType, utciEnv }) {
|
||||
export function buildHourlyRows({ forecast, airQuality, location, vehicleType, vehicleVent, vehicleSpeed, buildingType, furColor, utciEnv }) {
|
||||
const env = UTCI_ENVIRONMENTS[utciEnv] ?? UTCI_ENVIRONMENTS.open;
|
||||
const utcOffsetMs = (forecast?.utc_offset_seconds ?? 0) * 1000;
|
||||
|
||||
@@ -185,6 +187,11 @@ export function buildHourlyRows({ forecast, airQuality, location, vehicleType, v
|
||||
const indoorTemps = calcIndoorTempPass(TaArr, globArr, elevArr, buildingType);
|
||||
const managedTemps = calcManagedIndoorTempPass(TaArr, globArr, elevArr, buildingType);
|
||||
hourlyRows.forEach((r, i) => { r.indoorT = indoorTemps[i]; r.managedT = managedTemps[i]; });
|
||||
|
||||
// Fur surface temperature with thermal lag - Pets profile.
|
||||
const furAlbedo = (FUR_COLORS[furColor] || FUR_COLORS.brown).albedo;
|
||||
const furTemps = calcFurSurfaceTempPass(TaArr, radArr, vaArr, elevArr, furAlbedo);
|
||||
hourlyRows.forEach((r, i) => { r.furSurfaceT = furTemps[i]; });
|
||||
}
|
||||
|
||||
// Group those hourly rows into days for the day tabs.
|
||||
@@ -673,6 +680,56 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols
|
||||
];
|
||||
}
|
||||
|
||||
// ── Pets (cats / small dogs) ────────────────────────────────────────────
|
||||
if (profile === 'pets') {
|
||||
const peakFur = peakRow('furSurfaceT');
|
||||
const peakShade = peakRow('shadeT');
|
||||
const peakIndoor = peakRow('indoorT');
|
||||
const maxPollen = Math.max(0, ...todayRows.map(r => r.grassPollen ?? 0));
|
||||
const peakAqi = Math.max(0, ...todayRows.map(r => r.aqi ?? 0));
|
||||
const carDanger = todayRows.find(r => r.vehicleT != null && r.vehicleT >= 29);
|
||||
|
||||
return [
|
||||
...(show('furSurfaceT') ? [{
|
||||
icon: '🐾',
|
||||
label: 'Sunsoak for pet',
|
||||
value: peakFur ? `${Math.round(peakFur.furSurfaceT)}° at ${hhmm(peakFur.iso)}` : '-',
|
||||
alert: !!(peakFur && peakFur.furSurfaceT >= 45),
|
||||
}] : []),
|
||||
...(show('petShadeT') ? [{
|
||||
icon: '🌳',
|
||||
label: 'Shade for pet',
|
||||
value: peakShade ? `${Math.round(peakShade.shadeT)}° at ${hhmm(peakShade.iso)}` : '-',
|
||||
alert: !!(peakShade && peakShade.shadeT >= 26),
|
||||
}] : []),
|
||||
...(show('petHomeT') ? [{
|
||||
icon: '🏠',
|
||||
label: 'Pet at home',
|
||||
value: peakIndoor ? `${Math.round(peakIndoor.indoorT)}° at ${hhmm(peakIndoor.iso)}` : '-',
|
||||
alert: !!(peakIndoor && peakIndoor.indoorT >= 26),
|
||||
}] : []),
|
||||
...(show('vehicleT') ? [{
|
||||
icon: '🧒',
|
||||
label: 'Kids/pets in car',
|
||||
value: carDanger ? `Unsafe from ${hhmm(carDanger.iso)}` : 'Safe all day',
|
||||
alert: !!carDanger,
|
||||
}] : []),
|
||||
...lightningItem,
|
||||
...(show('aqi') ? [{
|
||||
icon: '💨',
|
||||
label: 'Air quality',
|
||||
value: peakAqi > 0 ? aqiLabel(peakAqi) : '-',
|
||||
alert: peakAqi >= 60,
|
||||
}] : []),
|
||||
...(show('pollen') && maxPollen >= 10 ? [{
|
||||
icon: '🌼',
|
||||
label: 'Pollen',
|
||||
value: pollenLabel(maxPollen),
|
||||
alert: maxPollen >= 50,
|
||||
}] : []),
|
||||
];
|
||||
}
|
||||
|
||||
// ── Activities - running / cycling ─────────────────────────────────────
|
||||
if (variant === 'running' || variant === 'cycling') {
|
||||
const coolWins = allWindows(dayRows, r =>
|
||||
|
||||
Reference in New Issue
Block a user