Files
HeatGuard/internal/heat/internal_gains.go
vikingowl 1c9db02334 feat: add web UI with full CRUD setup page
Add server-side rendered setup UI accessible via `heatwave web`.
The dashboard is now re-rendered per request and includes a nav bar
linking to the new /setup page. Setup provides full CRUD for profiles,
rooms, devices, occupants, AC units (with room assignment), scenario
toggles, and forecast fetching — all via POST/redirect/GET forms.

- Add ShowNav field to DashboardData for conditional nav bar
- Extract fetchForecastForProfile() for reuse by web handler
- Create setup.html.tmpl with Tailwind-styled entity sections
- Create web_handlers.go with 15 route handlers and flash cookies
- Switch web.go from pre-rendered to per-request dashboard rendering
- Graceful dashboard fallback when no forecast data exists
2026-02-09 10:39:00 +01:00

94 lines
2.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package heat
// DeviceMode selects which power draw to use for heat gain calculation.
type DeviceMode int
const (
ModeIdle DeviceMode = iota
ModeTypical
ModePeak
)
// Device represents a heat-producing device in a room.
type Device struct {
WattsIdle float64
WattsTypical float64
WattsPeak float64
DutyCycle float64 // 0.01.0
}
// ActivityLevel represents metabolic activity of room occupants.
type ActivityLevel int
const (
Sleeping ActivityLevel = iota
Sedentary
LightActivity
ModerateActivity
HeavyActivity
)
// metabolicWatts maps activity level to per-person heat output in watts.
var metabolicWatts = map[ActivityLevel]float64{
Sleeping: 70,
Sedentary: 100,
LightActivity: 130,
ModerateActivity: 200,
HeavyActivity: 300,
}
// Occupant represents people in a room.
type Occupant struct {
Count int
Activity ActivityLevel
}
// ParseActivityLevel converts a string to ActivityLevel.
func ParseActivityLevel(s string) ActivityLevel {
switch s {
case "sleeping":
return Sleeping
case "sedentary":
return Sedentary
case "light":
return LightActivity
case "moderate":
return ModerateActivity
case "heavy":
return HeavyActivity
default:
return Sedentary
}
}
// DeviceHeatGain returns heat output in watts for a device in the given mode.
func DeviceHeatGain(d Device, mode DeviceMode) float64 {
var base float64
switch mode {
case ModeIdle:
base = d.WattsIdle
case ModeTypical:
base = d.WattsTypical
case ModePeak:
base = d.WattsPeak
}
return base * d.DutyCycle
}
// OccupantHeatGain returns total metabolic heat output in watts.
func OccupantHeatGain(count int, activity ActivityLevel) float64 {
return float64(count) * metabolicWatts[activity]
}
// TotalInternalGains sums device and occupant heat gains in watts.
func TotalInternalGains(devices []Device, mode DeviceMode, occupants []Occupant) float64 {
var total float64
for _, d := range devices {
total += DeviceHeatGain(d, mode)
}
for _, o := range occupants {
total += OccupantHeatGain(o.Count, o.Activity)
}
return total
}