A Home Assistant integration for intelligent fresh air damper control based on indoor vs. outdoor environmental conditions.
Smart Fresh Air automatically controls a fresh air intake damper by comparing indoor and outdoor conditions (temperature, humidity, and air quality) to determine when bringing in outside air would be beneficial. The integration ensures a minimum amount of fresh air per hour while preventing uncomfortable or unhealthy conditions.
Key Features:
- Safety-first logic — Temperature extremes block fresh air intake unless there's an indoor air quality emergency
- Smart humidity comparison — Evaluates whether outdoor humidity will help or hurt indoor conditions
- Accurate fresh air tracking — Only counts fresh air time when your HVAC fan is actually running
- 20-minute hourly minimum — Ensures adequate fresh air while respecting blocking conditions
- Manual overrides — Force open/closed for 24 hours or indefinitely
- Detailed dashboard card — See exactly why the damper is open or closed
- Open HACS in Home Assistant
- Click Integrations → + Explore & Download Repositories
- Search for "Smart Fresh Air"
- Click Download
- Restart Home Assistant
- Download the
smart_fresh_airfolder from this repository - Copy it to your
config/custom_components/directory - Restart Home Assistant
After installation, add the integration via the UI:
- Go to Settings → Devices & Services → + Add Integration
- Search for "Smart Fresh Air"
- Follow the setup wizard:
Select the switch entity that controls your fresh air damper. This should be a Zigbee, Z-Wave, or WiFi switch wired to your damper actuator.
Note: The integration assumes a "power open" configuration where the switch being ON means the damper is OPEN.
Select your indoor and outdoor temperature and humidity sensors. These are typically provided by your thermostat integration (e.g., Daikin Skyport, Ecobee, Nest).
Select your outdoor AQI sensor. Indoor AQI is optional—many thermostats only provide outdoor air quality data.
Compatibility Note: Some integrations (like Daikin Skyport) use non-standard device classes for AQI sensors (e.g., "score" instead of "aqi"). The selector shows all sensors to accommodate this.
Select your HVAC airflow sensor (CFM). This enables accurate fresh air tracking—minutes are only counted when the fan is actually circulating air.
Why this matters: If your damper is open but the HVAC fan isn't running, no fresh air is actually being pulled in. This sensor ensures the "20 minutes per hour" goal represents actual air exchange.
Optionally add bedroom temperature/humidity sensors for future enhanced comfort logic.
The integration evaluates conditions in this order:
| Priority | Condition | Result |
|---|---|---|
| 1 | Manual override active | Follows override |
| 2 | Indoor AQI > 200 (Unhealthy) | OPEN regardless of temperature |
| 3 | Outdoor temp < 40°F or > 90°F | CLOSED (safety block) |
| 4 | Outdoor AQI > 150 (Unhealthy for Sensitive Groups) | CLOSED |
| 5 | Outdoor AQI significantly worse than indoor | CLOSED |
| 6 | Favorable conditions (score > 30) | OPEN |
| 7 | Minimum fresh air needed & no hard blocks | OPEN |
| 8 | Default | CLOSED |
Unlike simple "is outdoor humidity in range" checks, this integration compares indoor vs. outdoor humidity to determine if fresh air would help or hurt:
| Indoor Humidity | Outdoor Humidity | Result |
|---|---|---|
| Low (< 35%) | Higher than indoor | Favorable — will help humidify |
| Low (< 35%) | Lower than indoor | Blocking — won't help |
| High (> 55%) | Lower than indoor | Favorable — will help dehumidify |
| High (> 55%) | Higher than indoor | Blocking — will make it worse |
| Ideal (35-55%) | Reasonable range | Generally favorable |
Example: If your indoor humidity is 43% and outdoor is 89%, the integration recognizes this as favorable because the humid outdoor air will help raise indoor humidity toward the ideal 50%.
A composite score from -100 to +100 helps visualize the overall favorability:
- Temperature component (-40 to +20): Ideal range (55-78°F) scores highest
- AQI component (-40 to +40): Based on indoor vs. outdoor comparison
- Humidity component (-20 to +20): Based on whether outdoor air helps indoor conditions
The integration tracks minutes of fresh air per hour, but only counts time when:
- The damper is open, AND
- The HVAC fan is running (airflow ≥ 50 CFM)
This ensures the 20-minute goal represents actual air exchange, not just "damper open time."
The integration creates these entities:
| Entity | Type | Description |
|---|---|---|
binary_sensor.should_open |
Binary Sensor | Current decision (on = should be open) |
sensor.decision_score |
Sensor | Score from -100 to +100 |
sensor.decision_reason |
Sensor | Human-readable reason for current state |
sensor.fresh_air_this_hour |
Sensor | Minutes of fresh air this hour |
switch.fresh_air_damper |
Switch | Virtual switch (tap to set 24h override) |
select.override_mode |
Select | Override mode selector |
decision_reason/decision_reason_text— Why the damper is open/closeddecision_score— Composite favorability scoreblocking_factors— List of conditions preventing fresh airfavorable_factors— List of conditions favoring fresh airminutes_open_this_hour— Fresh air minutes this hourfan_is_running— Whether HVAC fan is currently oncurrent_airflow_cfm— Current airflow reading
A custom Lovelace card is included for detailed status visualization.
-
Add the card as a resource:
- Go to Settings → Dashboards → Resources
- Click + Add Resource
- URL:
/local/smart-fresh-air-card.js - Type: JavaScript Module
-
Add the card to your dashboard:
type: custom:smart-fresh-air-card
entity: binary_sensor.should_open
override_entity: select.override_mode
title: Fresh Air Damper- Status badge — OPEN (green) or CLOSED (gray)
- Override indicator — Shows when manual override is active
- Decision score bar — Visual -100 to +100 scale with color coding
- Current reason — Why the damper is in its current state
- Blocking/favorable factors — Detailed breakdown of decision inputs
- Quick override buttons — Auto, Open 24h, Close 24h
After initial setup, you can adjust thresholds via Settings → Devices & Services → Smart Fresh Air → Configure:
| Option | Default | Description |
|---|---|---|
| Minimum Safe Temp | 40°F | Below this, fresh air is blocked |
| Maximum Safe Temp | 90°F | Above this, fresh air is blocked |
| Min Fresh Air Minutes | 20 | Target fresh air per hour |
This section documents key architectural decisions for developers and contributors.
The decision logic uses a strict priority order rather than pure scoring because some conditions should always block fresh air regardless of other factors. A 30°F outdoor temperature should never result in an open damper just because the AQI score is favorable—the HVAC system would struggle to maintain comfort.
Exception: Indoor AQI emergencies (> 200) override temperature blocks because health takes priority over comfort at hazardous pollution levels.
Early versions used simple "is outdoor humidity between 25-70%" checks. This failed in real-world scenarios:
- Indoor at 43%, outdoor at 89% → Old logic: "Block, outdoor too humid"
- Reality: Bringing in humid air would help the dry indoor condition
The comparison-based approach asks "will this help or hurt?" rather than "is outdoor humidity ideal?"
The fresh air intake only works when the HVAC system is circulating air. Without fan detection, the "20 minutes per hour" goal was meaningless—the damper could be open for 20 minutes while the fan was off, providing zero fresh air.
By tracking actual airflow (≥ 50 CFM threshold), the integration ensures the goal represents real air exchange.
This feature requires:
- Complex state tracking (minutes per hour, override expiration)
- Multi-factor decision logic with priorities
- Comparison-based evaluations (not just threshold checks)
While possible with automations and helpers, it would be fragile and difficult to maintain. A custom integration provides:
- Proper state management via DataUpdateCoordinator
- Clean entity creation with appropriate device classes
- UI-based configuration flow
- Easy distribution via HACS
Many HVAC systems (including Daikin) can be configured to circulate air for N minutes per hour when not heating/cooling. This integration is designed to work with that pattern:
- Daikin circulates at the top of each hour
- Integration prioritizes opening damper during first 20 minutes of hour
- Fresh air tracking resets at hour boundaries
- Check that your damper switch entity is correct in the integration settings
- Verify the switch works manually via Home Assistant
- Check Home Assistant logs for errors from
smart_fresh_air
Some integrations use non-standard device classes (e.g., Daikin uses "score" instead of "aqi"). The AQI selector shows all sensors—search/filter for your AQI entity.
Verify that:
- The damper is actually open (check
switch.fresh_air_damper) - The HVAC fan is running (check
fan_is_runningattribute) - Airflow is above 50 CFM (check
current_airflow_cfmattribute)
- Verify the integration is set up and entities exist
- Check that entity IDs match your configuration (may vary based on setup)
- Clear browser cache and refresh
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Follow Home Assistant's integration development guidelines
- Test thoroughly with real hardware if possible
- Submit a pull request with a clear description
# Clone the repository
git clone https://github.com/innonate/smart_fresh_air.git
# Copy to your HA config for testing
cp -r smart_fresh_air/custom_components/smart_fresh_air ~/.homeassistant/custom_components/
# Enable debug logging
logger:
logs:
custom_components.smart_fresh_air: debugsmart_fresh_air/
├── __init__.py # Integration setup, platform forwarding
├── manifest.json # HACS/HA metadata
├── const.py # Constants, thresholds, enums
├── coordinator.py # Decision logic, state management
├── config_flow.py # UI configuration wizard
├── binary_sensor.py # "Should open" decision entity
├── sensor.py # Score, reason, minutes entities
├── switch.py # Virtual damper switch
├── select.py # Override mode selector
├── strings.json # Translation keys
└── translations/en.json # English translations
-
SmartFreshAirCoordinator (
coordinator.py): Core decision engine. Implements the priority-based logic, scoring, and state tracking. ExtendsDataUpdateCoordinatorfor efficient polling. -
SmartFreshAirConfigFlow (
config_flow.py): Multi-step configuration wizard using Home Assistant's config flow system.
MIT License — see LICENSE for details.
- Inspired by discussions in the Home Assistant community about ERV/HRV control
- Decision logic informed by EPA AQI guidelines and ASHRAE ventilation standards
- Built for use with Daikin Skyport but designed to work with any HVAC integration