HDS entities and field semantics¶
The Home Datastore (HDS) manages all entities that make up a Quilt installation. This page documents the main entity types, their important fields, how they map to Python model classes, and any behavioural semantics that are not obvious from field names alone.
Space¶
A Space is a zone within a Quilt installation, typically a room. Spaces are hierarchical: there is a root "home" space (no parent) and leaf room spaces (each with a parent_space_id). Most operations work with leaf spaces only. Space.is_room returns True for leaf spaces.
Python model: quilt_hp.models.space.Space
Fields¶
| Field | Type | Meaning |
|---|---|---|
id |
str |
Unique object ID (UUID) |
system_id |
str |
System this space belongs to |
name |
str |
Display name (e.g. "Living Room") |
parent_space_id |
str \| None |
Parent space ID; None for the root home space |
controls.hvac_mode |
HVACMode |
The mode the user has set: STANDBY, COOL, HEAT, AUTO, FAN |
controls.heating_setpoint_c |
float |
Heating setpoint in °C |
controls.cooling_setpoint_c |
float |
Cooling setpoint in °C |
controls.comfort_setting_id |
str |
ID of the currently active comfort preset |
controls.comfort_setting_override |
ComfortSettingOverride |
Why the active comfort setting differs from the schedule |
state.ambient_temperature_c |
float \| None |
Current measured temperature; None if no recent reading |
state.hvac_state |
HVACState |
What the system is actually doing (may differ from hvac_mode if e.g. deferred) |
settings.occupancy_mode |
OccupancyMode |
Whether auto-away/return is enabled |
settings.unoccupied_timeout_s |
float |
Seconds of no-presence before auto-away (default ~1200 s = 20 min) |
settings.occupied_timeout_s |
float |
Seconds of presence before auto-return (default ~180 s = 3 min) |
settings.safety_heating |
SafetyHeatingMode |
Freeze-protection mode |
Behavioural semantics¶
STANDBY vs. AWAY: Setting hvac_mode=STANDBY via UpdateSpace puts the room into plain off mode. It stays off regardless of occupancy. This is implemented by clearing comfort_setting_id (sending an empty string) in the wire diff. In contrast, AWAY mode is managed by the server's occupancy logic and preserves the active comfort setting ID. Space.is_off returns True for explicit STANDBY, Space.is_away returns True when the AWAY comfort preset is active.
UpdateSpace requires echoing settings fields: When calling UpdateSpace with a settings block, all existing settings fields must be echoed back (name, timezone, occupancy mode, timeouts, safety heating). The server replaces the entire settings sub-message, so absent fields are cleared to their proto3 defaults. This is why HomeDatastoreService.update_space_settings() reads all current settings from the snapshot_space parameter before building the diff.
AUTO mode gap enforcement: When mode is AUTO, the library enforces a minimum 2.5°C gap between heating and cooling setpoints: cool = max(cool, heat + 2.5). This matches the Quilt mobile app behaviour.
Temperature setpoint routing: The wire temperature_setpoint_c field is the "mode-relevant" setpoint. It is the heating setpoint when mode is HEAT and the cooling setpoint otherwise. Both heating_temperature_setpoint_c and cooling_temperature_setpoint_c are always sent.
Sentinel and placeholder values (UI handling)¶
The Quilt apps use several placeholder values to represent "not set", "ignored in this mode", or missing data. Treat these as metadata, not literal user targets.
| Sentinel | Where it appears | Python handling |
|---|---|---|
heating=8.0, cooling=40.0 |
SpaceControls/ComfortSetting for STANDBY |
SpaceControls.has_standby_sentinel_setpoints, ComfortSetting.has_standby_sentinel_setpoints |
heating=0.0, cooling=0.0 |
ComfortSettingType.UNSPECIFIED placeholder |
ComfortSetting.has_unspecified_setpoint_sentinels, ComfortSetting.has_placeholder_setpoints |
comfort_setting_id="" |
Manual/direct-control mode (no preset bound) | SpaceControls.has_linked_comfort_setting, SpaceControls.comfort_setting_id_or_none |
louver_fixed_position=0.0 with non-FIXED mode |
Louver position ignored for AUTO/SWEEP/CLOSED | IndoorUnitControls.louver_position_is_placeholder, ComfortSetting.louver_position_is_placeholder |
fan_speed_mode=0 |
Proto3 default = fan fields absent / unknown in sparse diff | IndoorUnitControls.fan_speed_is_placeholder |
fanSpeedMaxRpm=0.0 |
Indoor-unit hardware spec missing/unpopulated (KMP model) | Reserved constant: UNSET_MAX_FAN_SPEED_RPM_SENTINEL |
NaN in temperatures/energy |
Missing or invalid measurement samples | SpaceState.has_missing_ambient_temperature, SpaceState.has_missing_setpoint, EnergyBucket.has_missing_energy_value |
timestamp seconds 0 |
Proto timestamp unset (no check-in yet) | Parsed as None for model datetimes (updated_at, wifi_last_seen) |
| unknown schedule weekday | Invalid/unknown day in ordering logic | ScheduleWeekDay.weekday_sort_order maps to tail sentinel |
For display code, prefer the *_or_none helpers and sentinel predicates over direct field formatting.
IndoorUnit¶
An IndoorUnit is a wall-mounted mini-split head unit (7⅞ in tall × 38¼ in wide × 8³⁄₁₆ in deep). It is one of the slimmest heads on the market. Each IDU is rated at 9,000 BTU and operates between 27–48 dBA. It belongs to exactly one Space and one OutdoorUnit. IDUs contain a QuiltSmartModule (the connectivity and radar hardware) and have multiple sub-messages covering controls, state, settings, performance metrics, presence detection, and fault conditions.
Python model: quilt_hp.models.indoor_unit.IndoorUnit
Fields¶
| Field | Type | Meaning |
|---|---|---|
id |
str |
Unique object ID |
space_id |
str |
Space this IDU serves |
outdoor_unit_id |
str \| None |
Connected outdoor unit |
qsm_id |
str \| None |
Embedded QuiltSmartModule ID |
controls.fan_speed |
FanSpeed |
AUTO, QUIET, LOW, MEDIUM, HIGH, BLAST |
controls.louver_mode |
LouverMode |
CLOSED, SWEEP, FIXED, AUTO |
controls.louver_fixed_position |
float |
Position 0.0–1.0 when louver_mode=FIXED |
controls.led_color_code |
int |
RGBW packed colour (0 = black/off) |
controls.led_brightness |
float |
Brightness 0.0–1.0 |
controls.led_state |
LightState |
Explicit ON/OFF/UNSPECIFIED |
state.ambient_temperature_c |
float |
Temperature measured at the IDU |
state.ambient_humidity_percent |
float |
Relative humidity at the IDU |
state.updated_at |
datetime \| None |
Timestamp of last state update; used for online detection |
settings.presence_fence_left_m |
float |
Left boundary of presence detection zone in metres (0 = unconfigured) |
Online detection¶
IndoorUnit.is_online returns True if the IDU sent a state update within the last 5 minutes (matches the _ONLINE_THRESHOLD_MINUTES = 5 constant). An offline IDU's controls data is stale. IndoorUnit.led_on applies the online gate: it returns False for offline IDUs regardless of the LED color/brightness values.
LED state semantics¶
LED state can be expressed two ways depending on whether the mobile_led_scheduling_enabled Statsig feature gate is active:
- Explicit state (
led_state = ONorOFF): The server preserves brightness when the LED is turned off. Soled_brightness > 0does not mean the LED is on. - Legacy brightness-based (
led_state = UNSPECIFIED): LED is considered on whenled_color_code != 0ANDled_brightness > 0.
IndoorUnitControls.light_on handles both cases. Always use idu.led_on (which also applies the online gate) rather than checking brightness directly.
FanSpeed wire encoding¶
FanSpeed maps to two wire fields: fan_speed_mode (1=AUTO, 2=SETPOINT) and fan_speed_percent. The FanSpeed.to_wire() method returns the pair; FanSpeed.from_wire() decodes it. The mapping:
| FanSpeed | fan_speed_mode | fan_speed_percent |
|---|---|---|
| AUTO | 1 | 0.0 |
| QUIET | 2 | 0.20 |
| LOW | 2 | 0.40 |
| MEDIUM | 2 | 0.60 |
| HIGH | 2 | 0.80 |
| BLAST | 2 | 1.00 |
OutdoorUnit¶
The variable-speed compressor unit that provides heating and cooling capacity to all connected IDUs. Quilt sells two configurations: a 2-zone model (QO1-M2Z18-NC-NA, up to 18,000 BTU/h heating) and a 3-zone model (QO1-M3Z27-NC-NA, larger capacity). Both use R32 refrigerant and can operate down to -13°F while maintaining about 90% capacity. Hardware information (model SKU, serial number, firmware) comes from the outdoor_unit_hardware lookup map in the snapshot proto. It is not embedded in the main outdoor_units list. SystemSnapshot.from_proto() resolves this by building a hardware map.
Python model: quilt_hp.models.outdoor_unit.OutdoorUnit
| Field | Type | Meaning |
|---|---|---|
id |
str |
Unique object ID |
space_id |
str |
Associated space (home-level space) |
model_sku |
str \| None |
Hardware model number (e.g. QO1-M2Z18-NC-NA) |
serial_number |
str \| None |
Unit serial number |
firmware_version |
str \| None |
Current firmware version string |
firmware_update_info_id |
str \| None |
ID of pending firmware update entity, if any |
performance_data.compressor_frequency_hz |
float \| None |
Live compressor speed in Hz |
performance_data.ambient_temperature_c |
float \| None |
Outdoor ambient temperature |
performance_data.coil_temperature_c |
float \| None |
Refrigerant coil temperature |
Controller¶
The Quilt Dial is a compact circular thermostat (58 mm diameter) that can be wall-mounted or placed on a tabletop. It has a high-res OLED touchscreen, a rotary dial, and built-in sensors for ambient temperature, motion, and proximity. Each Controller is associated with one Space and reports its own ambient temperature independently of the IDU. The Dial is also the primary local control surface for room-by-room and whole-home adjustments.
Python model: quilt_hp.models.controller.Controller
| Field | Type | Meaning |
|---|---|---|
id |
str |
Unique object ID |
space_id |
str |
Space this Dial controls |
name |
str |
Display name |
ambient_temperature_c |
float |
Temperature measured by the Dial's built-in sensor |
raw_thermistor_c |
float |
Raw uncalibrated thermistor reading |
remote_sensor_mode |
HvacControllerType |
How the Dial's temperature reading influences the space setpoint |
model_sku |
str \| None |
Hardware model identifier |
serial_number |
str \| None |
Unit serial number |
software_update_info_id |
str \| None |
Pending software update entity ID |
firmware_update_info_id |
str \| None |
Pending firmware update entity ID |
QuiltSmartModule (QSM)¶
The intelligent compute and sensor module embedded inside each Indoor Unit. It runs the on-device occupancy logic, hosts the millimeter-wave radar presence sensor, and handles over-the-air firmware updates. The QSM exposes raw sensor readings that the server-side occupancy algorithm uses to decide when a room transitions between occupied and unoccupied states.
Python model: quilt_hp.models.qsm.QuiltSmartModule
| Field | Type | Meaning |
|---|---|---|
id |
str |
Unique object ID |
software_update_info_id |
str \| None |
Pending software update entity ID |
firmware_update_info_id |
str \| None |
Pending firmware update entity ID |
sensors.phase_detected_raw |
float \| None |
Raw phase-detection reading from the radar (motion indication) |
sensors.target_detected_raw |
float \| None |
Raw target-detection reading (presence indication, detects stationary people) |
sensors.als_illuminance_raw |
float \| None |
Raw ambient light sensor reading |
sensors.accel_x_raw |
float \| None |
Accelerometer X axis (used to detect unit orientation/mounting) |
sensors.accel_y_raw |
float \| None |
Accelerometer Y axis |
sensors.accel_z_raw |
float \| None |
Accelerometer Z axis |
The radar distinguishes between phase_detected (movement) and target_detected (presence including stationary humans up to 15 ft / 4.6 m away). That lets Auto-Away detect a person sitting still and reading a book, unlike PIR-based sensors that only respond to movement.
RemoteSensor and ControllerRemoteSensor¶
Wireless temperature/humidity sensors. RemoteSensor is a standalone sensor attached to an IDU; ControllerRemoteSensor is the temperature/humidity sensor embedded in the Dial itself.
Both report:
- ambient_temperature_c
- humidity_percent
- battery_level_percent
- signal_level_dbm
- control_mode: Whether this sensor is used as the zone temperature source
Python models: quilt_hp.models.sensor.RemoteSensor, ControllerRemoteSensor
ComfortSetting¶
A named comfort preset that can be assigned to a space or used in a schedule. Each preset defines a complete set of HVAC parameters. There are system-defined types (ACTIVE, SLEEP, AWAY, STANDBY) and user-defined CUSTOM presets.
Python model: quilt_hp.models.comfort.ComfortSetting
Fields¶
| Field | Type | Meaning |
|---|---|---|
id |
str |
Unique preset ID |
system_id |
str |
System this preset belongs to |
space_id |
str |
Space this preset is scoped to |
name |
str |
Display name |
type |
ComfortSettingType |
ACTIVE, SLEEP, AWAY, STANDBY, CUSTOM |
hvac_mode |
HVACMode |
HVAC mode for this preset |
heating_setpoint_c |
float |
Heating setpoint |
cooling_setpoint_c |
float |
Cooling setpoint |
fan_speed |
FanSpeed |
Fan speed |
ScheduleDay¶
A schedule day program is a named set of time-based events that set comfort presets and HVAC behaviour throughout the day. Each event specifies a start_s (seconds since midnight), an optional comfort_setting_id, and explicit hvac_mode, heating_temperature_setpoint_c, cooling_temperature_setpoint_c.
Python model: quilt_hp.models.schedule.ScheduleDay
Fields of ScheduleEvent:
- start_s: Offset in seconds from midnight when this event starts.
- comfort_setting_id: The comfort preset to activate (can be empty for explicit setpoints).
- hvac_mode, heating_setpoint_c, cooling_setpoint_c: Direct setpoint override.
- precondition: Whether to pre-condition the space before the event time.
ScheduleWeek¶
A schedule week assigns a ScheduleDay program to each day of the week. Each ScheduleWeekDay maps a weekday (enum: MON, TUE, WED, THU, FRI, SAT, SUN) to a day_id (the ID of a ScheduleDay).
Python model: quilt_hp.models.schedule.ScheduleWeek
Location¶
A Location is the top-level container for a Quilt installation. It stores the timezone and the global schedule execution state. Location.schedule_paused is True when all schedules are paused via UpdateLocation. SystemSnapshot.primary_location returns the first (typically only) location.
Python model: quilt_hp.models.system.Location