Added pets profile
This commit is contained in:
Fraxle
2026-07-09 16:04:55 +01:00
parent e4bdfb88c3
commit aee039ad61
6 changed files with 226 additions and 64 deletions
+60 -3
View File
@@ -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 =>