Files
HeatGuard/internal/compute/types.go
vikingowl 84d645ff21 feat: fix cold-weather thermal logic, add comfort mode, and dashboard forecast refresh
- Fix ComputeRoomBudget: no-AC rooms check if open-window ventilation
  can offset gains instead of defaulting to Overloaded. Net-cooling
  rooms are now Comfortable; ventilation-solvable rooms are Marginal.
- Add "comfort" cool mode for hours where outdoor is >5°C below indoor
  and budget is not overloaded (winter/cold scenarios).
- Reorder determineCoolMode: sealed now before overloaded, fixing
  humid+cold+no-AC giving "overloaded" instead of "sealed".
- Update LLM prompts: document comfort coolMode, add cold-weather
  guidance for summary and actions generation.
- Add dashboard forecast refresh button: fetches fresh forecast +
  warnings, then re-runs compute and LLM pipelines.
- Extract forecast fetch into shared fetchForecastForProfile() in db.js,
  deduplicating logic between setup.js and dashboard.js.
- Add indoor humidity support, pressure display, and cool mode sealed
  integration test.
2026-02-10 04:26:53 +01:00

179 lines
6.1 KiB
Go

package compute
import "time"
// Profile holds location profile data sent from the client.
type Profile struct {
ID int64 `json:"id"`
Name string `json:"name"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
Timezone string `json:"timezone"`
}
// Room holds room parameters sent from the client.
type Room struct {
ID int64 `json:"id"`
ProfileID int64 `json:"profileId"`
Name string `json:"name"`
AreaSqm float64 `json:"areaSqm"`
CeilingHeightM float64 `json:"ceilingHeightM"`
Floor int `json:"floor"`
Orientation string `json:"orientation"`
ShadingType string `json:"shadingType"`
ShadingFactor float64 `json:"shadingFactor"`
Ventilation string `json:"ventilation"`
VentilationACH float64 `json:"ventilationAch"`
WindowFraction float64 `json:"windowFraction"`
SHGC float64 `json:"shgc"`
Insulation string `json:"insulation"`
IndoorTempC float64 `json:"indoorTempC"`
IndoorHumidityPct *float64 `json:"indoorHumidityPct,omitempty"`
}
// Device holds device data sent from the client.
type Device struct {
ID int64 `json:"id"`
RoomID int64 `json:"roomId"`
Name string `json:"name"`
DeviceType string `json:"deviceType"`
WattsIdle float64 `json:"wattsIdle"`
WattsTypical float64 `json:"wattsTypical"`
WattsPeak float64 `json:"wattsPeak"`
DutyCycle float64 `json:"dutyCycle"`
}
// Occupant holds occupant data sent from the client.
type Occupant struct {
ID int64 `json:"id"`
RoomID int64 `json:"roomId"`
Count int `json:"count"`
ActivityLevel string `json:"activityLevel"`
Vulnerable bool `json:"vulnerable"`
}
// ACUnit holds AC unit data sent from the client.
type ACUnit struct {
ID int64 `json:"id"`
ProfileID int64 `json:"profileId"`
Name string `json:"name"`
ACType string `json:"acType"`
CapacityBTU float64 `json:"capacityBtu"`
HasDehumidify bool `json:"hasDehumidify"`
EfficiencyEER float64 `json:"efficiencyEer"`
}
// ACAssignment maps an AC unit to a room.
type ACAssignment struct {
ACID int64 `json:"acId"`
RoomID int64 `json:"roomId"`
}
// Forecast holds hourly forecast data sent from the client.
type Forecast struct {
Timestamp time.Time `json:"timestamp"`
TemperatureC *float64 `json:"temperatureC"`
HumidityPct *float64 `json:"humidityPct"`
CloudCoverPct *float64 `json:"cloudCoverPct"`
SunshineMin *float64 `json:"sunshineMin"`
ApparentTempC *float64 `json:"apparentTempC"`
PressureHpa *float64 `json:"pressureHpa"`
}
// Warning holds a weather warning sent from the client.
type Warning struct {
Headline string `json:"headline"`
Severity string `json:"severity"`
Description string `json:"description"`
Instruction string `json:"instruction"`
Onset string `json:"onset"`
Expires string `json:"expires"`
}
// ComputeRequest holds all data needed to compute a dashboard.
type ComputeRequest struct {
Profile Profile `json:"profile"`
Rooms []Room `json:"rooms"`
Devices []Device `json:"devices"`
Occupants []Occupant `json:"occupants"`
ACUnits []ACUnit `json:"acUnits"`
ACAssignments []ACAssignment `json:"acAssignments"`
Toggles map[string]bool `json:"toggles"`
Forecasts []Forecast `json:"forecasts"`
Warnings []Warning `json:"warnings"`
Date string `json:"date"`
}
// DashboardData holds all computed data for the dashboard response.
type DashboardData struct {
GeneratedAt time.Time `json:"generatedAt"`
ProfileName string `json:"profileName"`
Date string `json:"date"`
RiskLevel string `json:"riskLevel"`
PeakTempC float64 `json:"peakTempC"`
MinNightTempC float64 `json:"minNightTempC"`
PoorNightCool bool `json:"poorNightCool"`
IndoorTempC float64 `json:"indoorTempC"`
IndoorHumidityPct float64 `json:"indoorHumidityPct"`
Warnings []WarningData `json:"warnings"`
RiskWindows []RiskWindowData `json:"riskWindows"`
Timeline []TimelineSlotData `json:"timeline"`
RoomBudgets []RoomBudgetData `json:"roomBudgets"`
CareChecklist []string `json:"careChecklist"`
}
// WarningData holds a weather warning for display.
type WarningData struct {
Headline string `json:"headline"`
Severity string `json:"severity"`
Description string `json:"description"`
Instruction string `json:"instruction"`
Onset string `json:"onset"`
Expires string `json:"expires"`
}
// RiskWindowData holds a risk window for display.
type RiskWindowData struct {
StartHour int `json:"startHour"`
EndHour int `json:"endHour"`
PeakTempC float64 `json:"peakTempC"`
Level string `json:"level"`
Reason string `json:"reason"`
}
// TimelineSlotData holds one hour's data for the timeline.
type TimelineSlotData struct {
Hour int `json:"hour"`
HourStr string `json:"hourStr"`
TempC float64 `json:"tempC"`
HumidityPct float64 `json:"humidityPct"`
PressureHpa float64 `json:"pressureHpa"`
RiskLevel string `json:"riskLevel"`
BudgetStatus string `json:"budgetStatus"`
IndoorTempC float64 `json:"indoorTempC"`
CoolMode string `json:"coolMode"`
Actions []ActionData `json:"actions"`
}
// ActionData holds a single action for display.
type ActionData struct {
Name string `json:"name"`
Category string `json:"category"`
Effort string `json:"effort"`
Impact string `json:"impact"`
Description string `json:"description"`
}
// RoomBudgetData holds a room's heat budget for display.
type RoomBudgetData struct {
RoomName string `json:"roomName"`
InternalGainsW float64 `json:"internalGainsW"`
SolarGainW float64 `json:"solarGainW"`
VentGainW float64 `json:"ventGainW"`
TotalGainW float64 `json:"totalGainW"`
TotalGainBTUH float64 `json:"totalGainBtuh"`
ACCapacityBTUH float64 `json:"acCapacityBtuh"`
HeadroomBTUH float64 `json:"headroomBtuh"`
Status string `json:"status"`
}