Using Spaxiom for Demand-Responsive Climate Control and Energy Efficiency
Joe Scanlin
November 2025
Spaxiom is a sensor abstraction layer and runtime that translates billions of heterogeneous sensor streams into structured, semantic events. It provides a spatial-temporal DSL for defining zones, entities, and conditions, making it easy to build context-aware applications across industries.
INTENT (Intelligent Network for Temporal & Embodied Neuro-symbolic Tasks) is Spaxiom's high-level event vocabulary. Instead of overwhelming AI agents with raw sensor data, Spaxiom emits compact, meaningful events that agents can immediately understand and act upon.
Commercial buildings consume 40% of total U.S. energy, with HVAC systems accounting for 40–60% of that usage. Traditional Building Automation Systems (BAS) operate on fixed schedules and static temperature setpoints, conditioning empty spaces and responding slowly to occupancy changes. The challenge is that thermostats and VAV controllers run proprietary BACnet or Modbus protocols in isolated loops, occupancy sensors feed separate access control systems, CO₂ monitors log to dedicated IAQ platforms, and outdoor weather stations connect to independent forecast services—leaving AI agents unable to correlate real-time occupancy patterns with HVAC demand across fragmented building systems.
Spaxiom fuses occupancy sensors (motion, badge access, Wi-Fi/BLE tracking), indoor environmental quality monitors (temperature, humidity, CO₂, VOCs), HVAC system telemetry (AHU status, VAV damper positions, chiller loads), and outdoor weather feeds into one intelligent climate control platform. Instead of heating vacant conference rooms at 6 AM because of rigid schedules, it calculates a real-time "Comfort Efficiency Index" that balances occupant thermal comfort (PMV/PPD models) with energy consumption, predicting room usage patterns 30–60 minutes ahead. This sends control signals like "meeting room 4B unoccupied for next 2 hours—reduce setpoint to 18°C" or "east wing occupancy spike detected—pre-cool spaces now to avoid thermal lag," helping facility managers reduce HVAC energy costs by 20–35% while improving occupant comfort through responsive, human-centric climate control.
Commercial buildings (offices, hospitals, universities, retail) consume approximately 40% of total energy in developed nations, with Heating, Ventilation, and Air Conditioning (HVAC) systems representing 40–60% of building energy use. Traditional Building Automation Systems (BAS) operate on time-based schedules with fixed temperature setpoints, resulting in significant waste: conditioning spaces during unoccupied periods, failing to pre-cool/pre-heat before occupancy surges, and responding reactively to thermal discomfort complaints rather than proactively optimizing for predicted usage patterns.
Modern smart buildings integrate heterogeneous sensor networks spanning occupancy detection, environmental monitoring, and HVAC system state:
Legacy BAS protocols (BACnet, Modbus, LonWorks) operate in isolated control loops with limited cross-system integration. Spaxiom enables predictive, occupancy-driven HVAC orchestration by fusing real-time occupancy patterns, thermal comfort models, and HVAC system dynamics to minimize energy consumption while maintaining human-centric comfort standards.
The building HVAC domain defines semantic events that abstract low-level sensor data into actionable facility management directives:
ZoneOccupied / ZoneVacant: High-confidence occupancy state transitions based on multi-modal sensor fusion (motion + CO₂ rise + badge access). Includes occupancy count estimate and predicted duration (e.g., "meeting room occupied for next 90 min based on calendar integration").ThermalDiscomfort: Detected when Predicted Mean Vote (PMV) exceeds ±0.7 (outside ASHRAE 55 comfort range), indicating occupants likely experiencing thermal dissatisfaction. Includes root cause analysis (insufficient airflow, setpoint deviation, solar heat gain).VentilationDeficit: CO₂ concentration exceeds 1000 ppm (ASHRAE 62.1 guideline for acceptable IAQ), indicating inadequate outdoor air ventilation for current occupancy level. Triggers AHU outdoor air damper increase.PreConditioningRequired: Predictive event fired 30–60 minutes before anticipated occupancy surge (based on calendar, historical patterns, or detected arrival trends), allowing HVAC system to ramp thermal capacity before occupants arrive.EconomizerOpportunity: Outdoor air temperature and humidity conditions favorable for "free cooling"—meeting space cooling needs by increasing outdoor air intake rather than mechanical refrigeration. Significant energy savings during shoulder seasons.DemandResponseEvent: Utility-issued grid stress signal (peak demand period, high electricity price) triggers non-critical load shedding: raising cooling setpoints by 2–3°C, pre-cooling thermal mass before event, or shifting ventilation to minimum code requirements.These events enable closed-loop HVAC control, integration with calendar/scheduling systems for predictive conditioning, and participation in utility demand response programs for energy cost optimization.
Optimizing HVAC systems requires balancing two competing objectives: minimizing energy consumption while maintaining occupant thermal comfort. We compute a Comfort Efficiency Index (CEI) that quantifies this trade-off:
where each component is normalized to [0,1] with 1 = optimal performance:
Comfort Efficiency: Based on ASHRAE 55 Predicted Mean Vote (PMV) thermal comfort model:
where PMV is computed from operative temperature, humidity, air velocity, metabolic rate, and clothing insulation. PMV = 0 indicates thermal neutrality, PMV = ±0.5 is "slightly warm/cool" (acceptable), and |PMV| > 1.0 indicates discomfort. We set PMVmax = 1.5 for normalization.
The full PMV calculation (Fanger model) integrates six thermal factors:
where M is metabolic rate (W/m²), and L is the thermal load on the body accounting for convection, radiation, evaporation, and respiration heat exchange. Simplified for typical office environments (M ≈ 1.2 met, clothing ≈ 0.7 clo), PMV ≈ 0.5 · (Top − 23°C) where Top is operative temperature.
Energy Efficiency: Compares actual HVAC energy consumption to a baseline model:
where Eactual is measured HVAC power draw, Eoptimal is the theoretical minimum to maintain comfort given outdoor conditions and occupancy, and Ebaseline is historical energy use for the same conditions under legacy control (typically time-scheduled operation).
Indoor Air Quality: Weighted combination of CO₂, humidity, and VOC levels:
where CO₂excess = max(0, CO₂ − 800 ppm), ηRH penalizes humidity outside 30–60% range, and ηVOC normalizes total VOC concentration against health thresholds.
A CEI above 0.85 indicates optimal HVAC performance, 0.70–0.85 suggests tuning opportunities, below 0.70 triggers HvacInefficiency investigation.
The BuildingZone class demonstrates occupancy-driven HVAC optimization with predictive pre-conditioning:
from spaxiom import Sensor, Intent, Fusion, Metric, Zone
import math
from datetime import datetime, timedelta
class BuildingZone:
def __init__(self, zone_id, area_m2, design_occupancy):
self.zone_id = zone_id
self.area_m2 = area_m2
self.design_occupancy = design_occupancy
# Sensor streams
self.motion_sensors = [Sensor(f"pir_{i}") for i in range(4)]
self.badge_reader = Sensor("badge_access")
self.thermostat = Sensor("thermostat")
self.co2_sensor = Sensor("co2_monitor")
self.humidity_sensor = Sensor("humidity")
self.vav_box = Sensor("vav_controller") # Variable Air Volume
self.outdoor_weather = Sensor("weather_station")
# INTENT events
self.zone_occupied = Intent("ZoneOccupied")
self.zone_vacant = Intent("ZoneVacant")
self.thermal_discomfort = Intent("ThermalDiscomfort")
self.ventilation_deficit = Intent("VentilationDeficit")
self.preconditioning_required = Intent("PreConditioningRequired")
self.economizer_opportunity = Intent("EconomizerOpportunity")
# Fusion metrics
self.cei = Metric("comfort_efficiency_index", range=(0, 1))
self.pmv = Metric("predicted_mean_vote", range=(-3, 3))
self.occupancy_count = Metric("occupancy_estimate", range=(0, design_occupancy))
# State tracking
self.current_occupancy = 0
self.is_occupied = False
self.last_motion_time = None
self.co2_ppm = 400 # Outdoor baseline
self.temperature_c = 21
self.setpoint_c = 22
self.hvac_power_kw = 0
@Fusion.rule
def estimate_occupancy(self):
"""Multi-modal occupancy fusion from motion, CO₂, and badge access"""
# Motion-based occupancy (binary per sensor)
motion_active = sum(1 for sensor in self.motion_sensors
if sensor.latest().get("motion_detected", False))
motion_confidence = min(1.0, motion_active / len(self.motion_sensors))
# CO₂-based occupancy estimate (assumes ~35 L/h CO₂ per person)
co2_excess = max(0, self.co2_ppm - 400) # Above outdoor baseline
co2_occupancy_estimate = co2_excess / 35.0 # Rough person count
co2_confidence = min(1.0, co2_occupancy_estimate / self.design_occupancy)
# Badge access (recent entries minus exits)
badge_data = self.badge_reader.latest()
badge_count = badge_data.get("current_count", 0)
badge_confidence = 0.9 if badge_count > 0 else 0.1
# Weighted fusion (badge is most reliable, CO₂ and motion are supporting)
w_badge, w_co2, w_motion = 0.5, 0.3, 0.2
fused_confidence = (w_badge * badge_confidence +
w_co2 * co2_confidence +
w_motion * motion_confidence)
# Occupancy count estimate (prioritize badge count if available)
if badge_count > 0:
estimated_count = badge_count
else:
estimated_count = int(co2_occupancy_estimate)
self.current_occupancy = estimated_count
self.occupancy_count.update(estimated_count)
# Emit occupancy state transitions
newly_occupied = fused_confidence > 0.6 and not self.is_occupied
newly_vacant = fused_confidence < 0.3 and self.is_occupied
if newly_occupied:
self.is_occupied = True
self.zone_occupied.emit(
zone_id=self.zone_id,
occupancy_count=estimated_count,
confidence=fused_confidence,
timestamp=datetime.now()
)
elif newly_vacant:
self.is_occupied = False
self.zone_vacant.emit(
zone_id=self.zone_id,
vacant_duration_min=0, # Will be updated by timer
timestamp=datetime.now()
)
return estimated_count
@Fusion.rule
def calculate_pmv(self):
"""Compute Predicted Mean Vote thermal comfort index"""
# Simplified PMV for typical office (M=1.2 met, clo=0.7)
T_op = self.temperature_c # Operative temp ≈ air temp (low radiation)
rh = self.humidity_sensor.latest().get("relative_humidity", 50)
# Simplified Fanger model for sedentary office work
# PMV ≈ 0.5 * (T_op - T_neutral) adjusted for humidity
T_neutral = 23.0 # Thermal neutrality for office conditions
pmv_value = 0.5 * (T_op - T_neutral) + 0.01 * (rh - 50)
self.pmv.update(pmv_value)
# Detect thermal discomfort (|PMV| > 0.7 per ASHRAE 55)
if abs(pmv_value) > 0.7:
severity = "MINOR" if abs(pmv_value) < 1.0 else "MAJOR"
cause = "TOO_WARM" if pmv_value > 0 else "TOO_COLD"
self.thermal_discomfort.emit(
zone_id=self.zone_id,
pmv=pmv_value,
temperature_c=T_op,
setpoint_c=self.setpoint_c,
severity=severity,
cause=cause,
action="ADJUST_SETPOINT_OR_AIRFLOW"
)
return pmv_value
@Fusion.rule
def calculate_cei(self):
"""Compute Comfort Efficiency Index balancing comfort, energy, IAQ"""
# Comfort component (from PMV)
pmv_val = self.calculate_pmv()
eta_comfort = max(0, 1 - abs(pmv_val) / 1.5)
# Energy efficiency (compare to baseline)
# Baseline: 20 W/m² for typical office HVAC
E_baseline = 20 * self.area_m2 / 1000 # kW
E_actual = self.hvac_power_kw
# Optimal: scale with occupancy (empty space needs minimal conditioning)
occupancy_fraction = self.current_occupancy / self.design_occupancy
E_optimal = E_baseline * (0.3 + 0.7 * occupancy_fraction) # 30% base load
if E_baseline > 0:
eta_energy = max(0, 1 - (E_actual - E_optimal) / E_baseline)
else:
eta_energy = 1.0
# IAQ component
co2_excess = max(0, self.co2_ppm - 800)
eta_co2 = max(0, 1 - co2_excess / 600) # Penalty above 800 ppm
rh = self.humidity_sensor.latest().get("relative_humidity", 50)
if 30 <= rh <= 60:
eta_rh = 1.0
else:
eta_rh = max(0, 1 - abs(rh - 45) / 30)
eta_iaq = 0.7 * eta_co2 + 0.3 * eta_rh
# Weighted combination
w_C, w_E, w_Q = 0.4, 0.4, 0.2
cei_value = w_C * eta_comfort + w_E * eta_energy + w_Q * eta_iaq
self.cei.update(cei_value)
# Alert on inefficiency
if cei_value < 0.70:
Intent.emit("HvacInefficiency",
zone_id=self.zone_id,
cei=cei_value,
comfort_component=eta_comfort,
energy_component=eta_energy,
iaq_component=eta_iaq)
return cei_value
@Sensor.on_data("co2_monitor")
def monitor_ventilation(self, co2_ppm):
"""Detect inadequate ventilation and trigger outdoor air increase"""
self.co2_ppm = co2_ppm
# ASHRAE 62.1: 1000 ppm is typical upper limit for acceptable IAQ
if co2_ppm > 1000 and self.is_occupied:
severity = "CRITICAL" if co2_ppm > 1500 else "WARNING"
self.ventilation_deficit.emit(
zone_id=self.zone_id,
co2_ppm=co2_ppm,
threshold=1000,
occupancy_count=self.current_occupancy,
severity=severity,
action="INCREASE_OUTDOOR_AIR_DAMPER"
)
self.estimate_occupancy() # CO₂ is occupancy indicator
self.calculate_cei()
@Sensor.on_data("thermostat")
def monitor_temperature(self, temp_c, setpoint_c):
"""Track zone temperature and thermal comfort"""
self.temperature_c = temp_c
self.setpoint_c = setpoint_c
self.calculate_pmv()
self.calculate_cei()
@Sensor.on_data("vav_controller")
def monitor_hvac_power(self, airflow_cfm, reheat_kw, fan_power_kw):
"""Track HVAC energy consumption"""
self.hvac_power_kw = reheat_kw + fan_power_kw
self.calculate_cei()
@Sensor.on_data("weather_station")
def evaluate_economizer(self, outdoor_temp_c, outdoor_humidity):
"""Detect free cooling opportunities"""
indoor_temp = self.temperature_c
# Economizer opportunity: outdoor air cooler than indoor + within humidity range
if (outdoor_temp_c < indoor_temp - 2 and
outdoor_temp_c > 10 and # Not too cold (>50°F)
30 < outdoor_humidity < 70 and # Acceptable moisture
self.is_occupied):
potential_savings_kw = self.hvac_power_kw * 0.3 # Est. 30% savings
self.economizer_opportunity.emit(
zone_id=self.zone_id,
outdoor_temp=outdoor_temp_c,
indoor_temp=indoor_temp,
potential_savings_kw=potential_savings_kw,
action="INCREASE_OUTDOOR_AIR_FOR_FREE_COOLING"
)
def predict_occupancy(self, lookahead_minutes=60):
"""Predictive occupancy for pre-conditioning (simplified)"""
# In real implementation: integrate with calendar APIs, ML models
# For now: simple heuristic based on time of day
current_hour = datetime.now().hour
# Office building pattern
if 7 <= current_hour < 9: # Morning arrival
return int(self.design_occupancy * 0.8)
elif 12 <= current_hour < 13: # Lunch exodus
return int(self.design_occupancy * 0.3)
elif 17 <= current_hour < 19: # Evening departure
return int(self.design_occupancy * 0.2)
else:
return self.current_occupancy
# Example instantiation for 500 m² office zone
office_zone = BuildingZone(
zone_id="BLDG_A_FLOOR_3_WEST",
area_m2=500,
design_occupancy=50
)
Figure A.8 presents a comprehensive 24-hour HVAC optimization scenario for a commercial office zone. The visualization integrates four critical dimensions: occupancy pattern tracking from multi-modal sensor fusion, temperature control showing setpoint modulation responsive to occupancy state, HVAC energy consumption demonstrating demand-responsive load reduction, and the derived Comfort Efficiency Index (CEI). The annotated timeline shows how predictive pre-conditioning begins at 7:00 AM before occupant arrival, aggressive setback during the lunch vacancy period (12:00–13:00), and evening load shedding after 18:00 departure, achieving 30% energy savings compared to static schedule-based control while maintaining superior thermal comfort.
Figure A.8: Integrated occupancy-driven HVAC optimization for a 500 m² office zone (50-person capacity) over a typical workday. Panel 1: Multi-modal occupancy tracking fusing PIR motion sensors, badge access records, and CO₂-based estimates. Morning arrival surge (7:30–9:00) reaches 85% capacity, lunch exodus drops to 20%, afternoon plateau maintains 70–75%, and evening departure clears zone by 18:30. Confidence bands show sensor fusion uncertainty. Panel 2: Dynamic temperature control with occupancy-responsive setpoint modulation. Pre-conditioning begins at 6:45 AM (45 min before arrival) ramping from night setback (18°C) to comfort target (22°C). Aggressive setback during lunch vacancy (20°C) and evening unoccupied period (17°C) reduce HVAC load. Actual zone temperature (solid line) tracks setpoint with <1°C deviation, maintaining PMV within ±0.5 (ASHRAE 55 comfort range). Panel 3: HVAC energy consumption comparing occupancy-driven optimization (blue) to legacy schedule-based control (dashed gray). Peak demand reduction during vacant periods: lunch setback saves 8 kW (60% reduction), evening shutdown saves 12 kW (80% reduction). Cumulative daily energy: 180 kWh (optimized) vs. 260 kWh (baseline), representing 31% savings. Panel 4: Comfort Efficiency Index (CEI) composite score balancing thermal comfort (PMV-based), energy efficiency, and indoor air quality (CO₂, humidity). Morning pre-conditioning maintains CEI >0.85 despite energy ramp. Lunch period shows brief CEI dip (0.72) during aggressive setback for unoccupied space. Afternoon steady-state achieves optimal CEI 0.88–0.92. System demonstrates 30% energy savings while improving average thermal comfort (PMV σ reduced from 0.8 to 0.4) compared to static scheduling.
Building operators using Spaxiom-based occupancy-driven HVAC optimization have demonstrated:
The CEI metric provides a holistic performance indicator that bridges facility management (energy cost reduction), occupant experience (thermal comfort), and regulatory compliance (IAQ standards). By exposing actionable events like PreConditioningRequired, ZoneVacant, and EconomizerOpportunity, Spaxiom enables closed-loop HVAC orchestration that adapts in real time to building usage patterns. Integration with calendar systems (Outlook, Google Workspace) enables predictive conditioning based on scheduled meetings, while machine learning models trained on historical occupancy patterns forecast arrival/departure trends for proactive thermal management. This transforms buildings from reactive, schedule-driven HVAC operation to predictive, human-centric climate control that minimizes energy waste while maximizing occupant comfort and productivity.