View an example config flow with screenshots in the docs/setup.md file.
I ported this logic from a blueprint that @Ecronika shared in the Home Assistant Community Forums
There is already a custom integration named 'Thermal Comfort' that uses air temp and relative humidity to expose some perception sensors alongside dew point, frost point and heat index/humidex.
This integration is different in that it focuses on Mean Radiant Temperature (MRT) and Operative Temperature (
This integration brings a professional building science concept—Thermal Comfort—into Home Assistant. Instead of just showing the air temperature, this tool creates a Virtual Room Device that calculates how hot or cold a person actually feels.
-
Standard Thermometer: Measures Air Temperature (
$T_{air}$ ). 🌡️ -
Virtual Sensor: Measures Operative Temperature (
$T_{op}$ ), which is the most accurate single metric for human comfort, accounting for air temperature, the radiant heat from surrounding surfaces, and air velocity.
This is achieved by computing the Mean Radiant Temperature (MRT), which tracks the temperature of the walls, windows, and ceiling based on outside weather and sun exposure. ☀️
| Sensor | Definition | Use in HASS |
|---|---|---|
| Mean Radiant Temp (MRT) | The effective temperature of the room's surfaces (walls, windows, floor, ceiling). | Essential for monitoring radiant systems (floor heating/cooling). It allows you to see the thermal lag of your home's structure. 🐌 |
| Operative Temp ( |
The weighted average of the Air Temperature and the MRT. |
The ultimate trigger for HVAC automation. Use |
This integration exposes a Virtual Device for each room you configure. This device contains the calculated
The calculation relies on four primary configurable inputs (number entities) that represent the structural qualities of your room.
| Input Name | Layman's Explanation | Value Range | Example by Home Type |
|---|---|---|---|
|
Exterior Envelope Ratio ( |
Exterior Wall Share. How much of the room's total interior surface area touches the outside or an unconditioned space (like an attic or cold garage). | 0.15: Interior apartment room. 0.80: Corner room. 0.95: Top-floor attic room. | |
|
Window Share ( |
Window Ratio. The percentage of the exterior wall area that is glass. | 0.10: Small basement window. 0.50: Large picture window/patio door. 🖼️ | |
|
Insulation Loss Factor ( |
Heat Leakage / U-Value. How poorly insulated your walls and windows are, influencing heat loss in winter. (Higher value = worse insulation). | 0.10: Modern, well-insulated home. 0.25: Old, uninsulated walls. | |
|
Solar Gain Factor ( |
Solar Heating Power. How much solar energy actually passes through your windows to heat the room (often called SHGC). | 0.8: Standard clear glass. 1.5: Tilted skylight/very large clear windows. |
This input is critical for accurately modeling the room's thermal inertia (thermal mass).
| Input Name | Purpose | Suggested Range | Example by Home Type |
|---|---|---|---|
|
Thermal Smoothing Factor ( |
Controls how quickly the calculated MRT responds to changes in outside conditions (sun, wind). |
|
A North American 1950's wood-frame house has low thermal mass. You would use a higher |
- When you edit the
$\alpha$ factor, the change is immediate for the next calculation cycle. - However, the effect of the change on the sensor reading (
$\text{MRT}_{\text{final}}$ ) will be gradual because the smoothing formula is designed to integrate the new value slowly with the existing history. You will not see the MRT instantly jump.
The integration allows you to save a library of custom profiles per room.
- Profile Selector: The
select.profileentity lists all default profiles and any custom profiles you save. - Save/Delete: Use the
text.profile_nameinput and thebutton.save_profile/button.delete_profileentities to manage your library. - "Unsaved Custom Profile" State: If you select a default profile and manually change any of the four number inputs, the
select.profileentity will automatically switch its state to "Unsaved Custom Profile" (this is your working scratchpad). 💾- You can then input a profile name and save it as a new custom profile.
- There is a cap of 100 custom profiles per device (aka room).
The integration uses several optional inputs to dynamically calculate the effective Air Speed (
Note
The optional climate entity is only used to detect if the HVAC system is actively heating, cooling, or running the fan. It does not read or modify the target temperature or mode.
The final Air Speed (
| Input | Speed Contribution |
|---|---|
| Door State Sensor | If on: 0.8 m/s (Drafty). |
| Window State Sensor | If on: 0.5 m/s (Breezy). |
| HVAC Climate Entity | If hvac_action is active (heating/cooling/fan): Uses the HVAC Airflow Speed setting (default 0.4 m/s). Ignored if "Radiant Heating" is enabled. |
| Fan Entity | Uses mapped speed (low: 0.3, med: 0.5, high: 0.8). |
| Manual Air Speed | Uses the value set by the user (if > 0.1). |
| Default | 0.1 m/s (Still Air Baseline). |
If you have in-floor heating or radiators, the logic adapts.
- "Is Radiant Heating?" Checkbox: (In Config/Options Flow). If checked, the integration assumes the heating system warms the surfaces (MRT) rather than blowing air.
- Behavior: When
heatingis active:- Air Speed: Remains low (Still Air).
- MRT Boost: The calculated MRT is boosted based on the Radiant Surface Temperature target you set (e.g., 26°C for a warm floor).
- Thermal Capacitor: The boost is smoothed to simulate the slow heat-up and cool-down of the slab or radiator (configurable via Radiant System Type select).
- Shading Entity: Accepts a Cover, Binary Sensor, or Input Number.
- Effect: If the blinds are closed (0%), the Solar Gain term is multiplied by 0.0, stopping solar heating in the calculation. If 50% open, solar gain is cut by half.
The MRT calculation is reactive, meaning it constantly adjusts based on real-time weather conditions. For this, it pulls data from the Weather Entity, sun.sun and the optional Global Solar Radiation Sensor.
| Data Point | Source | Use in Calculation |
|---|---|---|
| Outdoor Air Temp ( |
weather entity attribute (temperature) |
Calculates the Heat Loss Term (how much heat escapes through the walls). |
| Apparent Temperature |
weather entity attribute (apparent_temperature) |
Used to determine effective heat loss. If Apparent Temp is lower than |
| Wind Speed / Wind Gust |
weather entity attribute (wind_speed, wind_gust_speed) |
Calculates the Wind Effect Factor (convective loss). Higher wind speed increases the heat loss from the exterior envelope. |
| Cloud Coverage / UV Index |
weather entity attributes or dedicated sensor
|
Used to estimate Global Solar Radiation (Solar Gain). |
| Precipitation / Condition |
weather entity state (rainy, snowy, etc.) |
Used to apply a Rain Multiplier (penalty) to the solar gain, simulating dark, wet conditions that reduce radiation transmission. |
| Sun Elevation | Home Assistant's sun.sun entity |
Determines the Daylight Factor, used as a multiplier for solar gain when the sun is below the horizon. |
| Sun Azimuth | Home Assistant's sun.sun entity |
Calculates the Solar Angle of Incidence Factor, used to determine how the sun is hitting the window |
| Global Solar Radiation | Optional dedicated sensor (e.g., sensor.solar_radiation) |
Preferred source for solar gain calculation. Bypasses all weather heuristics if available (will log a warning on values > 1300 W/m², but will still use it). |
Note
For best results, use a physical Total Solar Radiation Sensor (W/m²). These
sensors provide the most accurate measurement of solar radiation impacting your home.
If no sensor is supplied, the integration will intelligently estimate irradiance
using weather data, but cap it at 1000 W/m².
I don't have a physical one, so instead, I created a virtual sensor using the HASS built-in
Forcast.Solar integration. YOU MUST use 1000 as your
total watt peak power and 0 as your declination angle to get correct W/m² output for Global Horizontal
Irradiation (GHI), I left the default azimuth of 180.
I take the output sensor Estimated power production - now convert it's value directly to W/m² by using a
HASS helper template sensor and setting its device_class to irradiation and unit_of_measurement to W/m².
If the sensor outputs 123 W, it is converted to 123 W/m² and the template sensor is used as the dedicated Global Solar
Radiation Sensor in this integration.
The Mean Radiant Temperature (
-
Convective Weighting (
$A_{\text{Radiant}}$ ): The system first calculates the Radiant Weighting Factor ($A_{\text{Radiant}}$ ) based on the derived Air Speed ($v_{\text{air}}$ ) using ASHRAE simplified coefficients ($h_c$ and$h_r$ ):$$A_{\text{Radiant}} = \frac{h_r}{h_c + h_r}$$ -
Instantaneous Calculation (
$\text{MRT}_{\text{calc}}$ ): The physics model determines the raw temperature jump. The$\text{Solar}_{\text{term}}$ is multiplied by the Shading Factor, and the Radiant Boost is added if heating is active.
-
Clamping & Smoothing: The result is clamped to realistic bounds and smoothed by the Thermal Smoothing Factor (
$\alpha$ ).$\text{MRT}_{\text{final}}$ is the result.
-
Operative Temperature (
$T_{op}$ ): The final reported temperature uses the dynamic weighting derived in step 1.
If you configure a Relative Humidity (RH) Sensor in the integration settings, the device will automatically calculate and expose 7 additional advanced sensors. These are critical for holistic home health monitoring, mold prevention, and summer comfort control.
- How to Enable: In the Config Flow (or via "Configure"), select a sensor for Relative Humidity Source.
- Result: The integration immediately initializes the following sensors for that room.
| Sensor | Unit | What it tells you | Best Use Case |
|---|---|---|---|
|
Dew Point ( |
°C | The temperature at which condensation forms. |
Mold Prevention. If |
|
Frost Point ( |
°C | Similar to Dew Point, but for ice formation. |
Winter Safety. Monitor this in attics or near windows. If |
| Absolute Humidity | The actual mass of water vapor in the air volume. | Dehumidifier Control. Unlike RH, which changes with temperature, this tells you the actual moisture load. Use it to compare Indoor vs. Outdoor moisture to decide if opening a window will actually dry out the room. | |
|
Air Enthalpy ( |
The total heat energy (sensible + latent) stored in the air. | Efficiency. Used to control Energy Recovery Ventilators (ERVs) or Economizers. It tells you if the outside air actually has less energy than inside air, even if the temperature looks okay. | |
| Humidex | °C | A "feels-like" temperature combining heat and humidity. |
Summer Comfort. Use this to trigger Air Conditioning. High humidity makes |
| Thermal Perception | Text | A human-readable comfort status. |
Dashboards. Outputs states like "Comfortable", "Sticky", or "Dangerous". Great for quick-glance dashboards or sending phone notifications. |
Important
Technical Note: All psychrometric values are calculated using the Air Temperature (
Most "mold sensors" just alert you if the room humidity goes above 60%. This is often inaccurate in cold climates because mold doesn't start in the middle of the room—it starts on the coldest surface (thermal bridges, corners, or windows).
The Virtual Mold Risk Sensor uses your specific room parameters to calculate the relative humidity at the surface of your exterior walls, providing a much more accurate safety metric.
It combines four data points to model the microclimate at your wall's surface:
-
Indoor Air & Humidity: (
$T_{air}$ ,$RH$ ) -
Outdoor Temperature: (
$T_{out}$ from Weather Entity) -
Insulation Quality: (
$k_{loss}$ from your Configured Profile)
Using the Insulation Loss Factor (
The sensor reports the Surface Relative Humidity and assigns a risk level icon:
| Surface RH | Status | Icon | Meaning |
|---|---|---|---|
| < 65% | Low Risk | 🛡️ | Safe. No action needed. |
| 65% - 80% | Warning | Pre-conditions for mold. The surface is damp enough for spores to settle. You should lower indoor humidity or improve air circulation. | |
| > 80% | CRITICAL | ☣️ | Active Growth Potential. Conditions are perfect for mold germination on your walls. Immediate ventilation or dehumidification is required. |
Why this matters: In winter, a room at 45% RH might feel dry to you, but if your walls are cold, that same air can cause 90% RH at the wall surface, leading to hidden mold growth behind furniture. This sensor detects that invisible risk.
The original blueprint included logic to manually push values to a KNX Bus. Since this integration creates standard Home Assistant entities, you now use the native KNX Integration to expose these values.
To send the Mean Radiant Temperature or Operative Temperature to your KNX system (thermostats, displays, etc.), add the following to your configuration.yaml.
Data Point Type: The integration outputs values compatible with DPT 9.001 (Temperature °C).
# configuration.yaml
knx:
expose:
# Expose MRT to KNX
- type: temperature # DPT 9.001
address: "1/0/10" # Replace with your KNX Group Address
entity_id: sensor.living_room_mean_radiant_temperature
# Expose Operative Temperature (T_op) to KNX
- type: temperature # DPT 9.001
address: "1/0/11" # Replace with your KNX Group Address
entity_id: sensor.living_room_operative_temperature