A thirty-second look at what happens between the moment a guest mentions the pool and the moment they step outside on Friday afternoon.
Hi — can you heat the pool for our stay? Arriving Friday.
POST /webhook/hostaway
event: message.received
reservation: 71829
guest: "Meredith R."
→ scanMessagesForPoolHeat()
✓ intent: agreed confidence 0.94
// heater 400k BTU · 20k gal pool
dT = 18 °F
volume = 20,000 gal
loss = f(airTemp, wind, cover)
runtime ≈ 21 h ± 1.4 h
A production system running today at three short-term rentals in central Virginia. It ingests guest messages from Hostaway, classifies whether the guest is asking for pool heat, models the pool's thermodynamics against a real 72-hour weather forecast, and writes a heating schedule directly to the property's pool automation controller.
It's boring by design. It saves the owner from remembering to flip a breaker on Thursday night, and — more importantly — it saves her from forgetting to flip it off on Sunday. The second half is where the real margin lives: every forgotten-off day costs roughly forty dollars in propane.
Six real integrations. No mocks. The whole loop completes in under ninety seconds from message to committed schedule.
OmniLogic and AquaConnect already expose the primitives needed to run a system like this at scale: scheduling, setpoint control, remote diagnostics. What they don't ship — and what most property managers end up building badly in spreadsheets — is the booking-intent layer: the bridge between a guest's words and a controller's schedule.
Pool-heat-manager is a working reference implementation of that bridge. The hard parts are built: intent classification tuned on real guest language, a thermodynamic model that handles wind and cover state, and an idempotent schedule writer that survives controller reboots. For Hayward, this is a plug-in for the STR and property-management segment — a category no incumbent has seriously productized.
The repo is public. A single node service, TypeScript, roughly two thousand lines. github.com/kylehawke-stack/pool-heat-manager
export function heatUpRuntimeHours(p: {
currentF: number,
targetF: number,
gallons: number,
heaterBTU: number,
forecast: HourlyForecast[],
hasCover: boolean,
}): number {
const dT = p.targetF - p.currentF;
const mass = p.gallons * 8.34; // lb of water
const gross = (mass * dT) / p.heaterBTU; // hours, no loss
// loss term: convection+evap, simplified per ASHRAE
const lossPerHr = p.forecast
.map(h => hourlyLossBTU(h, p.targetF, p.hasCover))
.reduce((a,b) => a+b, 0) / p.forecast.length;
return gross / (1 - lossPerHr / p.heaterBTU);
}
Kyle Hawke — independent advisor. Former McKinsey Partner, channel strategy at STIHL.
kylehawke@gmail.comConsulting engagements on IoT + booking platforms — STR/PMS adjacent work welcome. Happy to walk the Hayward team through the repo on a call.