I have just looked at the thermal comfort integration. There is no reason this template should not work if you have the states correct.
Yes, this are the available values for the sensor. So i choosed the right sensor? There are a lot and with no air quality experience its not so easy.
Do you think thermal comfort could be of help or do you prefer calculating by yourself?
Thats what look for me like the dew point calculation:
async def dew_point(self) -> float:
"""Dew Point <http://wahiduddin.net/calc/density_algorithms.htm>."""
A0 = 373.15 / (273.15 + self._temperature)
SUM = -7.90298 * (A0 - 1)
SUM += 5.02808 * math.log(A0, 10)
SUM += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / A0))) - 1)
SUM += 8.1328e-3 * (pow(10, (-3.49149 * (A0 - 1))) - 1)
SUM += math.log(1013.246, 10)
VP = pow(10, SUM - 3) * self._humidity
Td = math.log(VP / 0.61078)
Td = (241.88 * Td) / (17.558 - Td)
return Td
Thermal Comfort would be of help, especially if you have all the states correct.
Only limitiation I see for Thermal Comfort is it only provides one sensor.
The dewpoint will be different in each area you are trying to measure. Ideally a separate dewpoint sensor is required for each area, which can be calculated with a manual template sensor or just using this integration.
In the below image you can see the difference between my areas
- Temperature Comfort Colour is the card background
- Dewpoint Comfort Colour is the colour inside
outer_ring:
- Top Right Sensor is DewPoint
- Top Left is Feels Like
you can add as much as you want. I have one for each room and one for outside.
Well that might be a good solution then. Do your cards look like above?
i try to find the right entities. Cards look similar, but no colors, no idea why, even not, if i add an else part with crimson color.
card_mod:
style: |
ha-card {
{% set state = states('sensor.thermal_comfort_kitchen_dew_point_perception') %}
{% if state =='Too Dry') %}
--ha-card-background: radial-gradient(circle, deepskyblue, 55%, black, black) !important;
{% elif state =='Comfy Dry') %}
--ha-card-background: radial-gradient(circle, mediumaquamarine, 55%, black, black) !important;
{% elif state =='Pleasant') %}
--ha-card-background: radial-gradient(circle, limegreen, 55%, black, black) !important;
{% elif state =='Comfortable') %}
--ha-card-background: radial-gradient(circle, yellowgreen, 55%, black, black) !important;
{% elif state =='Sticky Humid') %}
--ha-card-background: radial-gradient(circle, yellow, 55%, black, black) !important;
{% elif state =='Muggy') %}
--ha-card-background: radial-gradient(circle, gold, 55%, black, black) !important;
{% elif state =='Sweltering') %}
--ha-card-background: radial-gradient(circle, orange, 55%, black, black) !important;
{% elif state =='Stifling') %}
--ha-card-background: radial-gradient(circle, crimson, 55%, black, black) !important;
{% else) %}
--ha-card-background: radial-gradient(circle, crimson, 55%, black, black) !important;
{% endif %}
}
Description of available sensors: thermal_comfort/documentation/sensors.md at 437419ae35b56ae42b9cadc2577b95943f537e2f · dolezsa/thermal_comfort · GitHub
left/right mismatched?
Got it sorted and hope i use meaningful sensors using Integration thermal_comfort/documentation/sensors.md at 437419ae35b56ae42b9cadc2577b95943f537e2f · dolezsa/thermal_comfort · GitHub rather then dew point integration and nodeRed.
Unfortunately the entity_id naming was changed to use local names for ids rather then English ones for interchangeability/examples and so on. If you prefer English ids, change your HA language to English before adding thermal comfort integration entries (one for each room/outside). You can change it back later.
I would like to tint the white dot orange if there is mold risk, but i couldn’t find out how to change the dot color.
I am not sure if i need the dew point temperature. I may switch it with the difference between absolute humidity in- and outside.
type: picture-elements
image: local/overlay.svg
elements:
- type: custom:button-card
name: Card Title
label: Room 3
show_name: false
show_label: true
style:
left: 50%
top: 5%
width: 100%
styles:
label:
- font-size: 20px
- color: silver
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
name: Text Dew Point Comfort
entity: sensor.thermal_comfort_room_3_humidex_perception
label: Sensor from Integration Thermal Comfort
show_state: true
show_name: false
show_label: false
show_icon: false
style:
right: "-50%"
top: 13%
width: 100%
styles:
state:
- font-size: 25px
- font-weight: bold
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
name: Sensor 1 - Temperature
entity: sensor.atc_t3_temperature
show_state: true
show_name: false
show_icon: true
style:
left: 20%
top: 25%
width: 50%
transform: translate(-50%, -50%) scale(0.8, 0.8)
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
name: Sensor 2 - Humindex
entity: sensor.thermal_comfort_room_3_humidex
label: Sensor from Integration Thermal Comfort
show_state: true
show_name: false
show_icon: true
style:
left: 80%
top: 25%
width: 50%
transform: translate(-50%, -50%) scale(0.8, 0.8)
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
name: Sensor 3 - Humidity
entity: sensor.atc_t3_humidity
show_state: true
show_name: false
show_icon: true
style:
left: 20%
top: 75%
width: 50%
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
name: Sensor 4 - Dewpoint
entity: sensor.thermal_comfort_room_3_dew_point
label: Sensor from Integration Thermal Comfort
show_state: true
show_name: false
show_icon: true
style:
left: 80%
top: 75%
width: 50%
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
name: Text Dewpoint Comfort Sensor 3
entity: sensor.thermal_comfort_room_3_dew_point_perception
label: Sensor from Integration Thermal Comfort
show_state: true
show_name: false
show_label: false
show_icon: false
style:
left: 20%
top: 92%
width: 50%
styles:
state:
- font-size: 20px
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
name: Text Temperature Comfort Sensor 4
entity: sensor.thermal_comfort_room_3_summer_simmer_perception
label: Sensor from Integration Thermal Comfort
show_state: true
show_name: false
show_label: false
show_icon: false
style:
left: 80%
top: 92%
width: 50%
styles:
state:
- font-size: 20px
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
name: Outer Ring Limits
show_name: false
show_icon: false
aspect_ratio: 1/1
entity: sensor.thermal_comfort_room_3_dew_point_perception
label: Sensor from Integration Thermal Comfort
style:
right: 4.5%
top: 50%
height: 45%
width: 45%
styles:
card:
- border-radius: 50%
- border-width: 5px
- border-color: rgba(255,255,255,1)
card_mod:
style: |
ha-card {
{% set state = states('sensor.thermal_comfort_room_3_dew_point_perception') %}
{% set colors = {
'dry': 'deepskyblue',
'very_comfortable': 'mediumaquamarine',
'comfortable': 'limegreen',
'ok_but_humid': 'yellowgreen',
'somewhat_uncomfortable': 'yellow',
'quite_uncomfortable': 'gold',
'extremely_uncomfortable': 'orange',
'severely_high': 'crimson'}
%}
--ha-card-background: radial-gradient(circle, {{colors[state]}}, 55%, black, black) !important;
}
- type: custom:button-card
name: Inner Circle Comfort Zone
show_name: false
show_icon: false
aspect_ratio: 1/1
entity: sensor.thermal_comfort_room_3_dew_point_perception
label: Sensor from Integration Thermal Comfort
style:
right: 28.5%
top: 50%
height: 21%
width: 21%
styles:
card:
- border-radius: 50%
- border-width: 0px
card_mod:
style: |
ha-card {
--ha-card-background: radial-gradient(circle, black, black, grey ) !important;
{
- type: custom:button-card
name: Floating Circle
icon: mdi:circle
show_name: false
size: 25%
card_mod:
style: |
:host {
{% set humidity_float = states('sensor.atc_t3_humidity') | float %}
{% set temperature_float = states('sensor.atc_t3_temperature') | float %}
left: {{ 0.5 + humidity_float }}%;
bottom: {{((temperature_float-1.5)*(100-0)/(72.5-27.5))+0}}%;
transition: bottom 1s, left 1s;
}
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
label: Warm
show_label: true
style:
right: 0%
top: 22%
width: 50%
styles:
label:
- font-size: 20px
- color: grey
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
label: Cold
show_label: true
style:
right: 0%
top: 79%
width: 50%
styles:
label:
- font-size: 20px
- color: grey
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
label: Dry
show_label: true
style:
left: 22%
top: 50%
width: 20%
styles:
label:
- font-size: 20px
- color: grey
- writing-mode: vertical-rl
- transform: rotate(180deg)
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
- type: custom:button-card
label: Humid
show_label: true
style:
left: 79%
top: 50%
width: 20%
styles:
label:
- font-size: 20px
- color: grey
- writing-mode: vertical-rl
card_mod:
style: |
ha-card {
--ha-card-background: transparent !important;
}
card_mod:
style: |
ha-card {
{% set state = states('sensor.thermal_comfort_room_3_summer_simmer_perception') %}
{% set colors = {
'cool': 'dodgerblue',
'slightly_cool': 'deepskyblue',
'comfortable': 'mediumaquamarine',
'slightly_warm': 'seagreen',
'increasing_discomfort': 'gold',
'extremely_warm': 'orange',
'danger_of_heatstroke': 'crimson'}
%}
--ha-card-background: radial-gradient(circle, black, black, black, {{colors[state]}}) !important;
}
ha-card {
--ha-card-border-width: 0px !important;
--ha-card-border-radius: 5px !important;
--box-shadow: none !important;
}
V5.0 SIMPLE AIR COMFORT CARD
Horizontal Stack
Two Vertical Stacks within Horizontal Stack
-
Fully refactored code
- One card code for all screen sizes
- No NodeRED Dependency
- Minimal card-mod used (improves loading times)
- Previous card-mod code moved into button card native
- All border and background transparent
- Default white icons
- Error handling for unknown and unavailable sensors (text and colour)
- Improved scaling for (Floating Circle)
-
Macro Driven
- Most of the configuration of the card completed from the macro
- Calculates Dewpoint
- Calculates Feels like Temperature (Australian Apparent Temperature)
- Calculates Temperature Colour (Card Background)
- Calculates Dewpoint Colour (Outer Ring Limits)
- Calculates Temp and Humidity Alert Colour (Inner Circle Comfort Zone)
- Calculates Temperature and Humidity Position and Blinking Warning (Floating Circle)
- Configurable setpoints in the macros, to allow customisation.
-
Sensors that get inserted into the card
- Dewpoint
- Feels like Temperature (Australian Apparent Temperature)
- Temperature Colour (Card Background)
- Dewpoint Colour (Outer Ring Limits)
- Temp and Humidity Alert Colour (Inner Circle Comfort Zone)
- Temperature and Humidity Position and Blinking Warning (Floating Circle)
Background Overlay
- Using Visual Studio Code Editor or other, create a new folder called
simple-air-comfort-card
inconfig/www/community
- Right Click on you newly created folder
/config/www/community/simple-air-comfort-card
and select New File - Name the new file
sac_background_overlay.svg
- Click on the file and paste the following:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150" />
MACRO CODE
- Using Visual Studio Code Editor or other, create a new folder called
custom_templates
in yourconfig
, if it is not already there. - Right Click on you newly created folder
/config/custom_templates
and select New File - Name the new file
sac_macros.jinja
5. Click on the file and paste the following:
MACRO CODE
{# Dewpoint Temperature #}
{% macro calculate_dew_point(entity_temperature, entity_humidity) %}
{% set T, RH = states(entity_temperature), states(entity_humidity) %}
{% if (T == 'unknown') or (RH == 'unknown') %}
unknown
{% elif (T == 'unavailable') or (RH == 'unavailable') %}
unavailable
{% else %}
{% set T = T | float %}
{% set RH = RH | float %}
{# Arden Buck Method constants #}
{% set a = 6.1121 | float %}
{% set b = 18.678 | float %}
{% set c = 257.14 | float %}
{% set d = 234.5 | float %}
{% set e = 2.71828 | float %}
{# Calculate gamma #}
{% set gamma = log((RH/100)*e**((b-T/d)*(T/(c+T)))) | float %}
{# Calculate dew point #}
{% set dew_point = ((c * gamma) / (b - gamma)) | round(1) %}
{{ dew_point }}
{% endif %}
{% endmacro %}
{# Australian Apparent Temperature Feels Like #}
{% macro calculate_apparent_temperature(entity_temperature, entity_humidity, entity_wind_speed=None, Q=0) %}
{% set T, RH = states(entity_temperature), states(entity_humidity) %}
{% if (T == 'unknown') or (RH == 'unknown') %}
unknown
{% elif (T == 'unavailable') or (RH == 'unavailable') %}
unavailable
{% else %}
{% set T = T | float %}
{% set RH = RH | float %}
{% if entity_wind_speed %}
{% set WS = states(entity_wind_speed) %}
{% if (WS == 'unknown') or (WS == 'unavailable') %}
{% set WS = 0 %}
{% else %}
{% set WS = (WS | float) / 3.6 %} {# Convert km/h to m/s #}
{% endif %}
{% else %}
{% set WS = 0 %}
{% endif %}
{# Calculate water vapor pressure (e) #}
{% set e = (RH / 100) * 6.105 * (2.71828 ** ((17.27 * T) / (237.7 + T))) %}
{# Calculate apparent temperature (AT) #}
{% set AT = T + 0.348 * e - 0.70 * WS + 0.70 * (Q / (WS + 10)) - 4.25 %}
{{ AT | round(1) }}
{% endif %}
{% endmacro %}
{# Dewpoint Comfort Text #}
{% macro calculate_text_dewpoint_comfort(sensor_dewpoint) %}
{# Retrieve the current state of the dew point sensor #}
{% set dewpoint = states(sensor_dewpoint) %}
{# Check for 'unknown' or 'unavailable' states first #}
{% if dewpoint == 'unknown' %}
{% set comfort_level = 'Unknown' %}
{% elif dewpoint == 'unavailable' %}
{% set comfort_level = 'Unavailable' %}
{% else %}
{# Convert the dew point value to float and categorize it #}
{% set dewpoint = dewpoint | float(0) %}
{% if dewpoint < 5 %}
{% set comfort_level = 'Very Dry' %}
{% elif dewpoint >= 5 and dewpoint <= 10 %}
{% set comfort_level = 'Dry' %}
{% elif dewpoint >= 10.1 and dewpoint <= 12.79 %}
{% set comfort_level = 'Pleasant' %}
{% elif dewpoint >= 12.8 and dewpoint <= 15.49 %}
{% set comfort_level = 'Comfortable' %}
{% elif dewpoint >= 15.5 and dewpoint <= 18.39 %}
{% set comfort_level = 'Sticky Humid' %}
{% elif dewpoint >= 18.4 and dewpoint <= 21.19 %}
{% set comfort_level = 'Muggy' %}
{% elif dewpoint >= 21.2 and dewpoint <= 23.9 %}
{% set comfort_level = 'Sweltering' %}
{% else %}
{% set comfort_level = 'Stifling' %}
{% endif %}
{% endif %}
{# Return the comfort level text #}
{{ comfort_level }}
{% endmacro %}
{# Temperature Comfort Text #}
{% macro calculate_text_temperature_comfort(sensor_temperature) %}
{# Retrieve the current state of the temperature sensor #}
{% set temperature = states(sensor_temperature) %}
{# Check for 'unknown' or 'unavailable' states first #}
{% if temperature == 'unknown' %}
{% set comfort_level = 'N/A' %}
{% elif temperature == 'unavailable' %}
{% set comfort_level = 'N/A' %}
{% else %}
{# Convert the temperature value to float and categorize it #}
{% set temperature = temperature | float(0) %}
{% if temperature < 3 %}
{% set comfort_level = 'FROSTY' %}
{% elif temperature >= 3.1 and temperature <= 4.9 %}
{% set comfort_level = 'COLD' %}
{% elif temperature >= 5 and temperature <= 8.9 %}
{% set comfort_level = 'CHILLY' %}
{% elif temperature >= 9 and temperature <= 13.9 %}
{% set comfort_level = 'COOL' %}
{% elif temperature >= 14 and temperature <= 18.9 %}
{% set comfort_level = 'MILD' %}
{% elif temperature >= 19 and temperature <= 23.9 %}
{% set comfort_level = 'PERFECT' %}
{% elif temperature >= 24 and temperature <= 27.9 %}
{% set comfort_level = 'WARM' %}
{% elif temperature >= 28 and temperature <= 34.9 %}
{% set comfort_level = 'HOT' %}
{% else %}
{% set comfort_level = 'BOILING' %}
{% endif %}
{% endif %}
{# Return the comfort level text #}
{{ comfort_level }}
{% endmacro %}
{# Humidity Comfort Text #}
{% macro calculate_text_humidity_comfort(entity_humidity) %}
{# Get the current humidity value from the specified entity_humidity #}
{% set humidity = states(entity_humidity) %}
{# Check for 'unknown' or 'unavailable' states first #}
{% if humidity == 'unknown' %}
N/A
{% elif humidity == 'unavailable' %}
N/A
{% else %}
{# Convert the humidity value to float and categorize it #}
{% set humidity = humidity | float(0) %}
{# Check if the humidity is less than 40% #}
{% if humidity < 40 %}
DRY
{# Check if the humidity is between 40% and 60% #}
{% elif humidity >= 40 and humidity <= 60 %}
COMFY
{# If the humidity is greater than 60% #}
{% else %}
HUMID
{% endif %}
{% endif %}
{% endmacro %}
{# SAC Card Picture Elements Card Background #}
{% macro calculate_temperature_colour_card_background(entity) %}
{% if is_state(entity, 'Unknown') or is_state(entity, 'Unavailable') or is_state(entity, 'N/A') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), dimgray) !important;
{% elif is_state(entity, 'FROSTY') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), mediumblue) !important;
{% elif is_state(entity, 'COLD') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), dodgerblue) !important;
{% elif is_state(entity, 'CHILLY') %}
--ha-card-background: radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), deepskyblue) !important;
{% elif is_state(entity, 'COOL') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), mediumaquamarine) !important;
{% elif is_state(entity, 'MILD') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), seagreen) !important;
{% elif is_state(entity, 'PERFECT') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), limegreen) !important;
{% elif is_state(entity, 'WARM') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), gold) !important;
{% elif is_state(entity, 'HOT') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), orange) !important;
{% elif is_state(entity, 'BOILING') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), crimson) !important;
{% endif %}
{% endmacro %}
{# SAC Card Element Outer Ring Limits #}
{% macro calculate_dewpoint_colour_outer_ring_limits(entity) %}
{# Set a default value for dewpoint_color #}
{% set dewpoint_color = 'radial-gradient(circle, transparent, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% if is_state(entity, 'Unknown') or is_state(entity, 'Unavailable') or is_state(entity, 'N/A') or is_state(entity, 'unavailable') or is_state(entity, 'unknown') %}
{% set dewpoint_color = 'radial-gradient(circle, dimgray, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Very Dry') %}
{% set dewpoint_color = 'radial-gradient(circle, deepskyblue, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Dry') %}
{% set dewpoint_color = 'radial-gradient(circle, mediumaquamarine, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Pleasant') %}
{% set dewpoint_color = 'radial-gradient(circle, limegreen, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Comfortable') %}
{% set dewpoint_color = 'radial-gradient(circle, yellowgreen, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Sticky Humid') %}
{% set dewpoint_color = 'radial-gradient(circle, yellow, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Muggy') %}
{% set dewpoint_color = 'radial-gradient(circle, gold, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Sweltering') %}
{% set dewpoint_color = 'radial-gradient(circle, orange, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Stifling') %}
{% set dewpoint_color = 'radial-gradient(circle, crimson, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% endif %}
{# Apply gradient #}
{{ dewpoint_color }}
{% endmacro %}
{# SAC Card Element Inner Circle Comfort Zone #}
{% macro inner_circle_comfort_zone_alert_colour(humidity_entity, temperature_entity) %}
{% set humidity_state = states(humidity_entity) %}
{% set temperature_state = states(temperature_entity) %}
{# Alert Levels #}
{% set temp_boiling_alert = 34.9 %}
{% set temp_hot_alert = 28.0 %}
{% set temp_warm_alert = 24.0 %}
{% set temp_mild_alert = 19.0 %}
{% set temp_cool_alert = 14.0 %}
{% set temp_chilly_alert = 9.0 %}
{% set temp_cold_alert = 5.0 %}
{% set temp_frosty_alert = 3.0 %}
{% set humidity_min_alert = 40 %}
{% set humidity_max_alert = 60 %}
{# Default colors for unknown/unavailable states #}
{% set default_color = 'dimgray' %}
{# Determine humidity colour #}
{% if humidity_state == 'unknown' or humidity_state == 'unavailable' %}
{% set humidity_color = default_color %}
{% else %}
{% set humidity_float = humidity_state | float(0) %}
{% if humidity_float > humidity_max_alert %}
{% set humidity_color = 'hotpink' %}
{% elif humidity_float >= humidity_min_alert and humidity_float <= humidity_max_alert %}
{% set humidity_color = 'black' %}
{% elif humidity_float < humidity_min_alert %}
{% set humidity_color = 'hotpink' %}
{% endif %}
{% endif %}
{# Determine temperature colour #}
{% if temperature_state == 'unknown' or temperature_state == 'unavailable' %}
{% set temperature_color = default_color %}
{% else %}
{% set temperature_float = temperature_state | float(0) %}
{% if temperature_float > temp_boiling_alert %}
{% set temperature_color = 'rgba(255, 69, 0, 0.8)' %}
{% elif temperature_float > temp_hot_alert and temperature_float <= temp_boiling_alert %}
{% set temperature_color = 'rgba(255, 69, 0, 0.8)' %}
{% elif temperature_float > temp_warm_alert and temperature_float <= temp_hot_alert %}
{% set temperature_color = 'dimgray' %}
{% elif temperature_float > temp_mild_alert and temperature_float <= temp_warm_alert %}
{% set temperature_color = 'dimgray' %}
{% elif temperature_float > temp_cool_alert and temperature_float <= temp_mild_alert %}
{% set temperature_color = 'rgba(0, 102, 255, 0.8)' %}
{% elif temperature_float > temp_chilly_alert and temperature_float <= temp_cool_alert %}
{% set temperature_color = 'rgba(0, 102, 255, 0.8)' %}
{% elif temperature_float > temp_cold_alert and temperature_float <= temp_chilly_alert %}
{% set temperature_color = 'rgba(0, 102, 255, 0.8)' %}
{% elif temperature_float > temp_frosty_alert and temperature_float <= temp_cold_alert %}
{% set temperature_color = 'rgba(0, 102, 255, 0.8)' %}
{% elif temperature_float < temp_frosty_alert %}
{% set temperature_color = 'rgba(0, 102, 255, 0.8)' %}
{% endif %}
{% endif %}
{# Apply gradient with spaces #}
radial-gradient(circle, {{ humidity_color }} 0%, black, {{ temperature_color }} 70%) !important;
{% endmacro %}
{# SAC Card Element Floating Circle #}
{% macro card_mod_floating_circle_movement_and_color(humidity_entity, temperature_entity) %}
{% set humidity_state = states(humidity_entity) %}
{% set temperature_state = states(temperature_entity) %}
{% set humidity_float = humidity_state | float(50) if humidity_state not in ['unknown', 'unavailable'] else 50 %}
{% set temperature_float = temperature_state | float(22.5) if temperature_state not in ['unknown', 'unavailable'] else 22.5 %}
{# Alert Levels and scaling factors #}
{% set temp_min = 14 %}
{% set temp_max = 35 %}
{% set temp_min_warning = 18 %}
{% set temp_max_warning = 27.9 %}
{% set humidity_min = 40 %}
{% set humidity_max = 60 %}
{# Scaling Map temp to 0% (bottom) → 100% (top) of the card #}
{% set temp_scaled = (((temperature_float - temp_min) * (100 - 0) / (temp_max - temp_min)) + 0) | round(1) %}
{% set temp_scaled = [0, temp_scaled, 100] | sort | join(' ') | regex_replace('^.*? (.*?) .*$', '\\1') %}
{# Check if the Floating Circle is outside Outer Ring Limits Temp or Inner Circle Comfort Zone Humidity #}
{% set outside_limits = (humidity_float < humidity_min) or (humidity_float > humidity_max) or (temperature_float < temp_min_warning) or (temperature_float > temp_max_warning) or (humidity_float == 50) or (temperature_float == 22.5) %}
{# Positioning the floating circle #}
left: {{ humidity_float + 0.5 }}%;
bottom: {{ temp_scaled }}%;
transition: bottom 0.8s ease-in-out, left 0.8s ease-in-out;
{# Ensures the icon itself does NOT blink #}
ha-icon {
color: white !important;
}
{# Default state: Fully transparent #}
ha-card {
border-radius: 50%;
background: transparent !important;
position: relative;
aspect-ratio: 1 / 1;
width: 100%;
height: auto;
}
{# When outside limits, apply blinking red gradient #}
{% if outside_limits %}
ha-card::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
aspect-ratio: 1 / 1;
width: 100%;
height: 100%;
background: radial-gradient(circle,
rgba(255,0,0,0.8) 20%,
rgba(255,0,0,0.3) 50%,
rgba(255,0,0,0.1) 70%,
rgba(255,0,0,0) 100%
) !important;
animation: blink 1s infinite alternate;
}
{% endif %}
{# Define blinking animation #}
@keyframes blink {
0% { opacity: 1; }
100% { opacity: 0.3; }
}
{% endmacro %}
SENSOR CODE
- In your
configuration.yaml
file paste the followingtemplate:
sensors:
into your configuration to make a single card. - Ensure you enter your Temperature and Humidity Sensors.
- Any sensors that start with
sensor.sac
are calculated in the Macro. - Rename i.e.
living_room
to suit your needs
SENSOR CODE
template:
- sensor:
# Template Dew Point Sensors - Utilising custom_templates/macros.jinja
- name: "dewpoint_living_room"
unique_id: c5e921de-47d2-4338-9158-8097911df43e
unit_of_measurement: "°C"
icon: mdi:thermometer-water
state: >
{% from 'sac_macros.jinja' import calculate_dew_point %}
{{ calculate_dew_point('sensor.insert_temperature', 'sensor.insert_humidity') }}
# Template Simple Air Comfort Card - Dewpoint Colour - Outer Ring Limits - Living Room
- name: "sac_dewpoint_colour_living_room"
unique_id: c6639b18-ac02-441f-badd-815c6c810254
state: >-
{% from 'sac_macros.jinja' import calculate_dewpoint_colour_outer_ring_limits %}
{{ calculate_dewpoint_colour_outer_ring_limits('sensor.sac_text_dewpoint_comfort_living_room') }}
# Template Simple Air Comfort Card - Alert Colour - Inner Circle - Living Room
- name: "sac_inner_circle_alert_colour_living_room"
unique_id: a3c9d6d1-e51d-450b-a61c-1f7d9cc7baeb
state: >-
{% from 'sac_macros.jinja' import inner_circle_comfort_zone_alert_colour %}
{{ inner_circle_comfort_zone_alert_colour('sensor.air_conditioning_humidity', 'air_conditioning_temperature') }}
# Template Simple Air Comfort Card - Temperature Colour - Picture Elements Card Background - Living Room
- name: "sac_temperature_colour_living_room"
unique_id: dc6c834b-f775-4b36-a2f3-d43356632cc6
state: >-
{% from 'sac_macros.jinja' import calculate_temperature_colour_card_background %}
{{ calculate_temperature_colour_card_background('sensor.sac_text_temperature_comfort_living_room') }}
# Template Simple Air Comfort Card - Text Dewpoint Comfort - Living Room
- name: "sac_text_dewpoint_comfort_living_room"
unique_id: e8b76541-7fe7-407e-b53d-f012a3d6152b
state: >-
{% from 'sac_macros.jinja' import calculate_text_dewpoint_comfort %}
{{ calculate_text_dewpoint_comfort('sensor.dewpoint_living_room') }}
# Template Simple Air Comfort Card - Text Temperature Comfort - Living Room
- name: "sac_text_temperature_comfort_living_room"
unique_id: 5e2b7728-1630-4d3f-b511-04d48bf76cd4
state: >-
{% from 'sac_macros.jinja' import calculate_text_temperature_comfort %}
{{ calculate_text_temperature_comfort('sensor.air_conditioning_temperature') }}
# Template Simple Air Comfort Card - Text Humidity Comfort - Living Room
- name: "sac_text_humidity_comfort_living_room"
unique_id: f299c759-e50c-4f9f-a775-b99734dab132
state: >-
{% from 'sac_macros.jinja' import calculate_text_humidity_comfort %}
{{ calculate_text_humidity_comfort('sensor.air_conditioning_humidity') }}
Thanks @LiQuid_cOOled for the input and @vajdum, may be of interest to you.
FINALLY V5.0 SIMPLE AIR COMFORT CARD
- Paste the following code into your lovelace dashboard view
- Only thing that needs to be changed is the word
living_room
to suit your needs, also add your temperature and humidity sensors. - Any sensors that start with
sensor.sac
are calculated in the Macro.
SIMPLE AIR COMFORT CARD YAML
- type: picture-elements
image: >-
local/community/simple-air-comfort-card/sac_background_overlay.svg
card_mod:
style: |
ha-card {
--ha-card-background: {{states('sensor.sac_temperature_colour_living_room')}}
--ha-card-border-width: 0px !important;
--ha-card-border-radius: 5px !important;
--box-shadow: none !important;
}
elements:
- type: custom:button-card
name: Card Title
label: Living Room
show_name: false
show_label: true
style:
left: 50%
top: 5%
width: 100%
transform: translate(-50%, -50%) scale(0.7, 0.7)
styles:
card:
- background: transparent
- border-color: transparent
label:
- color: silver
- type: custom:button-card
name: Text Dew Point Comfort - Living Room
entity: sensor.sac_text_dewpoint_comfort_living_room
label: >-
configuration.yaml template text sensor, calculated
from sac_macro.jinja
show_state: true
show_name: false
show_label: false
show_icon: false
style:
right: '-50%'
top: 14%
width: 100%
transform: translate(-50%, -50%) scale(0.95, 0.95)
styles:
card:
- background: transparent
- border-color: transparent
state:
- font-weight: bold
- type: custom:button-card
name: Sensor 1 - Dewpoint - Living Room
entity: sensor.dewpoint_living_room
label: >-
configuration.yaml template dewpoint sensor,
calculated from sac_macro.jinja
icon: mdi:water-thermometer-outline
show_state: true
show_name: false
show_icon: true
show_label: false
style:
left: 20%
top: 25%
width: 50%
transform: translate(-50%, -50%) scale(0.6, 0.6)
styles:
card:
- background: transparent
- border-color: transparent
icon:
- color: auto
- type: custom:button-card
name: Sensor 2 - Feels Like - Living Room
entity: sensor.living_room_feels_like_temperature
icon: tc:thermal-perception-alternative
show_state: true
show_name: false
show_icon: true
style:
left: 80%
top: 25%
width: 50%
transform: translate(-50%, -50%) scale(0.6, 0.6)
styles:
card:
- background: transparent
- border-color: transparent
icon:
- color: auto
- type: custom:button-card
name: Sensor 3 - Temperature - Living Room
entity: sensor.air_conditioning_temperature
show_state: true
show_name: false
show_icon: true
style:
left: 20%
top: 75%
width: 50%
transform: translate(-50%, -50%) scale(0.8, 0.8)
styles:
card:
- background: transparent
- border-color: transparent
icon:
- color: auto
- type: custom:button-card
name: Sensor 4 - Humidity - Living Room
entity: sensor.air_conditioning_humidity
show_state: true
show_name: false
show_icon: true
style:
left: 80%
top: 75%
width: 50%
transform: translate(-50%, -50%) scale(0.8, 0.8)
styles:
card:
- background: transparent
- border-color: transparent
icon:
- color: auto
- type: custom:button-card
name: Text Temperature Comfort Sensor 3 - Living Room
entity: sensor.sac_text_temperature_comfort_living_room
label: >-
configuration.yaml template text sensor, calculated
from sac_macro.jinja
show_state: true
show_name: false
show_label: false
show_icon: false
style:
left: 20%
top: 92%
width: 50%
transform: translate(-50%, -50%) scale(0.9, 0.9)
styles:
card:
- background: transparent
- border-color: transparent
- type: custom:button-card
name: Text Humidity Comfort Sensor 4 - Living Room
entity: sensor.sac_text_humidity_comfort_living_room
label: >-
configuration.yaml template text sensor, calculated
from sac_macro.jinja
show_state: true
show_name: false
show_label: false
show_icon: false
style:
left: 80%
top: 92%
width: 50%
transform: translate(-50%, -50%) scale(0.9, 0.9)
styles:
card:
- background: transparent
- border-color: transparent
- type: custom:button-card
name: Outer Ring Limits
show_name: false
show_icon: false
aspect_ratio: 1/1
style:
right: 4.5%
top: 50%
height: 45%
width: 45%
styles:
card:
- border-radius: 50%
- border-width: 2.5px
- border-color: rgba(255,255,255,1)
card_mod:
style: |
ha-card {
--ha-card-background: {{states('sensor.sac_dewpoint_colour_living_room')}}
}
- type: custom:button-card
name: Inner Circle Comfort Zone
show_name: false
show_icon: false
aspect_ratio: 1/1
style:
right: 28.5%
top: 50%
height: 21%
width: 21%
styles:
card:
- border-radius: 50%
- border-width: 0px
card_mod:
style: |
ha-card {
--ha-card-background: {{states('sensor.sac_inner_circle_alert_colour_living_room')}}
}
- type: custom:button-card
name: Floating Circle
icon: mdi:circle
show_name: false
show_icon: true
style:
width: 10%
height: 10%
transform: translate(-50%, -50%)
styles:
card:
- background: transparent
- border-color: transparent
card_mod:
style: |
:host {
{% from 'sac_macros.jinja' import card_mod_floating_circle_movement_and_color %}
{{ card_mod_floating_circle_movement_and_color('sensor.air_conditioning_humidity', 'sensor.air_conditioning_temperature') }}
}
- type: custom:button-card
label: Warm
show_label: true
style:
right: 0%
top: 22%
width: 50%
transform: translate(-50%, -50%) scale(0.7, 0.7)
styles:
label:
- color: grey
card:
- background: transparent
- border-color: transparent
- type: custom:button-card
label: Cold
show_label: true
style:
right: 0%
top: 79%
width: 50%
transform: translate(-50%, -50%) scale(0.7, 0.7)
styles:
label:
- color: grey
card:
- background: transparent
- border-color: transparent
- type: custom:button-card
label: Dry
show_label: true
style:
left: 22%
top: 50%
width: 20%
transform: translate(-50%, -50%) scale(0.7, 0.7)
styles:
label:
- color: grey
- writing-mode: vertical-rl
- transform: rotate(180deg)
card:
- background: transparent
- border-color: transparent
- type: custom:button-card
label: Humid
show_label: true
style:
left: 79%
top: 50%
width: 20%
transform: translate(-50%, -50%) scale(0.7, 0.7)
styles:
label:
- color: grey
- writing-mode: vertical-rl
card:
- background: transparent
- border-color: transparent
Solid work by @Chykan
V5.1 SIMPLE AIR COMFORT CARD
- Increased
floating circle
to 20px size - Improved centering of flashing red, moved into card-mod css, from custom button card.
- Flashing starts when
floating circle
breaches top ofouter ring limits
26.5 - High Temp Alert when
floating circle
breaches top ofouter ring limits
26.5 - Default center temperature 22
Horizontal Stack
Two Vertical Stacks within Horizontal Stack
- Fully refactored code
- One card code for all screen sizes
- No NodeRED Dependency
- Minimal card-mod used (improves loading times)
- Previous card-mod code moved into button card native
- All border and background transparent
- Default white icons
- Error handling for unknown and unavailable sensors (text and colour)
- Improved scaling for (Floating Circle)
- Macro Driven
- Most of the configuration of the card completed from the macro
- Calculates Dewpoint
- Calculates Feels like Temperature (Australian Apparent Temperature)
- Calculates Temperature Colour (Card Background)
- Calculates Dewpoint Colour (Outer Ring Limits)
- Calculates Temp and Humidity Alert Colour (Inner Circle Comfort Zone)
- Calculates Temperature and Humidity Position and Blinking Warning (Floating Circle)
- Configurable setpoints in the macros, to allow customisation.
- Sensors that get inserted into the card
- Dewpoint
- Feels like Temperature (Australian Apparent Temperature)
- Temperature Colour (Card Background)
- Dewpoint Colour (Outer Ring Limits)
- Temp and Humidity Alert Colour (Inner Circle Comfort Zone)
- Temperature and Humidity Position and Blinking Warning (Floating Circle)
Background Overlay
- Using Visual Studio Code Editor or other, create a new folder called
simple-air-comfort-card
inconfig/www/community
- Right Click on you newly created folder
/config/www/community/simple-air-comfort-card
and select New File - Name the new file
sac_background_overlay.svg
- Click on the file and paste the following:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150" />
MACRO CODE
- Using Visual Studio Code Editor or other, create a new folder called
custom_templates
in yourconfig
, if it is not already there. - Right Click on you newly created folder
/config/custom_templates
and select New File - Name the new file
sac_macros.jinja
- Click on the file and paste the following: MACRO CODE
Macro Code
{# Dewpoint Temperature #}
{% macro calculate_dew_point(entity_temperature, entity_humidity) %}
{% set T, RH = states(entity_temperature), states(entity_humidity) %}
{% if (T == 'unknown') or (RH == 'unknown') %}
unknown
{% elif (T == 'unavailable') or (RH == 'unavailable') %}
unavailable
{% else %}
{% set T = T | float %}
{% set RH = RH | float %}
{# Arden Buck Method constants #}
{% set a = 6.1121 | float %}
{% set b = 18.678 | float %}
{% set c = 257.14 | float %}
{% set d = 234.5 | float %}
{% set e = 2.71828 | float %}
{# Calculate gamma #}
{% set gamma = log((RH/100)*e**((b-T/d)*(T/(c+T)))) | float %}
{# Calculate dew point #}
{% set dew_point = ((c * gamma) / (b - gamma)) | round(1) %}
{{ dew_point }}
{% endif %}
{% endmacro %}
{# Australian Apparent Temperature Feels Like #}
{% macro calculate_apparent_temperature(entity_temperature, entity_humidity, entity_wind_speed=None, Q=0) %}
{% set T, RH = states(entity_temperature), states(entity_humidity) %}
{% if (T == 'unknown') or (RH == 'unknown') %}
unknown
{% elif (T == 'unavailable') or (RH == 'unavailable') %}
unavailable
{% else %}
{% set T = T | float %}
{% set RH = RH | float %}
{% if entity_wind_speed %}
{% set WS = states(entity_wind_speed) %}
{% if (WS == 'unknown') or (WS == 'unavailable') %}
{% set WS = 0 %}
{% else %}
{% set WS = (WS | float) / 3.6 %} {# Convert km/h to m/s #}
{% endif %}
{% else %}
{% set WS = 0 %}
{% endif %}
{# Calculate water vapor pressure (e) #}
{% set e = (RH / 100) * 6.105 * (2.71828 ** ((17.27 * T) / (237.7 + T))) %}
{# Calculate apparent temperature (AT) #}
{% set AT = T + 0.348 * e - 0.70 * WS + 0.70 * (Q / (WS + 10)) - 4.25 %}
{{ AT | round(1) }}
{% endif %}
{% endmacro %}
{# Dewpoint Comfort Text #}
{% macro calculate_text_dewpoint_comfort(sensor_dewpoint) %}
{# Retrieve the current state of the dew point sensor #}
{% set dewpoint = states(sensor_dewpoint) %}
{# Check for 'unknown' or 'unavailable' states first #}
{% if dewpoint == 'unknown' %}
{% set comfort_level = 'Unknown' %}
{% elif dewpoint == 'unavailable' %}
{% set comfort_level = 'Unavailable' %}
{% else %}
{# Convert the dew point value to float and categorize it #}
{% set dewpoint = dewpoint | float(0) %}
{% if dewpoint < 5 %}
{% set comfort_level = 'Very Dry' %}
{% elif dewpoint >= 5 and dewpoint <= 10 %}
{% set comfort_level = 'Dry' %}
{% elif dewpoint >= 10.1 and dewpoint <= 12.79 %}
{% set comfort_level = 'Pleasant' %}
{% elif dewpoint >= 12.8 and dewpoint <= 15.49 %}
{% set comfort_level = 'Comfortable' %}
{% elif dewpoint >= 15.5 and dewpoint <= 18.39 %}
{% set comfort_level = 'Sticky Humid' %}
{% elif dewpoint >= 18.4 and dewpoint <= 21.19 %}
{% set comfort_level = 'Muggy' %}
{% elif dewpoint >= 21.2 and dewpoint <= 23.9 %}
{% set comfort_level = 'Sweltering' %}
{% else %}
{% set comfort_level = 'Stifling' %}
{% endif %}
{% endif %}
{# Return the comfort level text #}
{{ comfort_level }}
{% endmacro %}
{# Temperature Comfort Text #}
{% macro calculate_text_temperature_comfort(sensor_temperature) %}
{# Retrieve the current state of the temperature sensor #}
{% set temperature = states(sensor_temperature) %}
{# Check for 'unknown' or 'unavailable' states first #}
{% if temperature == 'unknown' %}
{% set comfort_level = 'N/A' %}
{% elif temperature == 'unavailable' %}
{% set comfort_level = 'N/A' %}
{% else %}
{# Convert the temperature value to float and categorize it #}
{% set temperature = temperature | float(0) %}
{% if temperature < 3 %}
{% set comfort_level = 'FROSTY' %}
{% elif temperature >= 3.1 and temperature <= 4.9 %}
{% set comfort_level = 'COLD' %}
{% elif temperature >= 5 and temperature <= 8.9 %}
{% set comfort_level = 'CHILLY' %}
{% elif temperature >= 9 and temperature <= 13.9 %}
{% set comfort_level = 'COOL' %}
{% elif temperature >= 14 and temperature <= 18.9 %}
{% set comfort_level = 'MILD' %}
{% elif temperature >= 19 and temperature <= 23.9 %}
{% set comfort_level = 'PERFECT' %}
{% elif temperature >= 24 and temperature <= 27.9 %}
{% set comfort_level = 'WARM' %}
{% elif temperature >= 28 and temperature <= 34.9 %}
{% set comfort_level = 'HOT' %}
{% else %}
{% set comfort_level = 'BOILING' %}
{% endif %}
{% endif %}
{# Return the comfort level text #}
{{ comfort_level }}
{% endmacro %}
{# Humidity Comfort Text #}
{% macro calculate_text_humidity_comfort(entity_humidity) %}
{# Get the current humidity value from the specified entity_humidity #}
{% set humidity = states(entity_humidity) %}
{# Check for 'unknown' or 'unavailable' states first #}
{% if humidity == 'unknown' %}
N/A
{% elif humidity == 'unavailable' %}
N/A
{% else %}
{# Convert the humidity value to float and categorize it #}
{% set humidity = humidity | float(0) %}
{# Check if the humidity is less than 40% #}
{% if humidity < 40 %}
DRY
{# Check if the humidity is between 40% and 60% #}
{% elif humidity >= 40 and humidity <= 60 %}
COMFY
{# If the humidity is greater than 60% #}
{% else %}
HUMID
{% endif %}
{% endif %}
{% endmacro %}
{# SAC Card Picture Elements Card Background #}
{% macro calculate_temperature_colour_card_background(entity) %}
{% if is_state(entity, 'Unknown') or is_state(entity, 'Unavailable') or is_state(entity, 'N/A') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), dimgray) !important;
{% elif is_state(entity, 'FROSTY') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), mediumblue) !important;
{% elif is_state(entity, 'COLD') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), dodgerblue) !important;
{% elif is_state(entity, 'CHILLY') %}
--ha-card-background: radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), deepskyblue) !important;
{% elif is_state(entity, 'COOL') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), mediumaquamarine) !important;
{% elif is_state(entity, 'MILD') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), seagreen) !important;
{% elif is_state(entity, 'PERFECT') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), limegreen) !important;
{% elif is_state(entity, 'WARM') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), gold) !important;
{% elif is_state(entity, 'HOT') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), orange) !important;
{% elif is_state(entity, 'BOILING') %}
radial-gradient(circle, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15), crimson) !important;
{% endif %}
{% endmacro %}
{# SAC Card Element Outer Ring Limits #}
{% macro calculate_dewpoint_colour_outer_ring_limits(entity) %}
{# Set a default value for dewpoint_color #}
{% set dewpoint_color = 'radial-gradient(circle, transparent, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% if is_state(entity, 'Unknown') or is_state(entity, 'Unavailable') or is_state(entity, 'N/A') or is_state(entity, 'unavailable') or is_state(entity, 'unknown') %}
{% set dewpoint_color = 'radial-gradient(circle, dimgray, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Very Dry') %}
{% set dewpoint_color = 'radial-gradient(circle, deepskyblue, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Dry') %}
{% set dewpoint_color = 'radial-gradient(circle, mediumaquamarine, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Pleasant') %}
{% set dewpoint_color = 'radial-gradient(circle, limegreen, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Comfortable') %}
{% set dewpoint_color = 'radial-gradient(circle, yellowgreen, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Sticky Humid') %}
{% set dewpoint_color = 'radial-gradient(circle, yellow, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Muggy') %}
{% set dewpoint_color = 'radial-gradient(circle, gold, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Sweltering') %}
{% set dewpoint_color = 'radial-gradient(circle, orange, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% elif is_state(entity, 'Stifling') %}
{% set dewpoint_color = 'radial-gradient(circle, crimson, 55%, rgba(100, 100, 100, 0.15), rgba(100, 100, 100, 0.15)) !important;' %}
{% endif %}
{# Apply gradient #}
{{ dewpoint_color }}
{% endmacro %}
{# SAC Card Element Inner Circle Comfort Zone #}
{% macro inner_circle_comfort_zone_alert_colour(humidity_entity, temperature_entity) %}
{% set humidity_state = states(humidity_entity) %}
{% set temperature_state = states(temperature_entity) %}
{# Alert Levels #}
{% set temp_boiling_alert = 34.9 %}
{% set temp_hot_alert = 26.5 %}
{% set temp_warm_alert = 24.0 %}
{% set temp_mild_alert = 19.0 %}
{% set temp_cool_alert = 14.0 %}
{% set temp_chilly_alert = 9.0 %}
{% set temp_cold_alert = 5.0 %}
{% set temp_frosty_alert = 3.0 %}
{% set humidity_min_alert = 40 %}
{% set humidity_max_alert = 60 %}
{# Default colors for unknown/unavailable states #}
{% set default_color = 'dimgray' %}
{# Determine humidity colour #}
{% if humidity_state == 'unknown' or humidity_state == 'unavailable' %}
{% set humidity_color = default_color %}
{% else %}
{% set humidity_float = humidity_state | float(0) %}
{% if humidity_float > humidity_max_alert %}
{% set humidity_color = 'hotpink' %}
{% elif humidity_float >= humidity_min_alert and humidity_float <= humidity_max_alert %}
{% set humidity_color = 'black' %}
{% elif humidity_float < humidity_min_alert %}
{% set humidity_color = 'hotpink' %}
{% endif %}
{% endif %}
{# Determine temperature colour #}
{% if temperature_state == 'unknown' or temperature_state == 'unavailable' %}
{% set temperature_color = default_color %}
{% else %}
{% set temperature_float = temperature_state | float(0) %}
{% if temperature_float > temp_boiling_alert %}
{% set temperature_color = 'rgba(255, 69, 0, 0.8)' %}
{% elif temperature_float > temp_hot_alert and temperature_float <= temp_boiling_alert %}
{% set temperature_color = 'rgba(255, 69, 0, 0.8)' %}
{% elif temperature_float > temp_warm_alert and temperature_float <= temp_hot_alert %}
{% set temperature_color = 'dimgray' %}
{% elif temperature_float > temp_mild_alert and temperature_float <= temp_warm_alert %}
{% set temperature_color = 'dimgray' %}
{% elif temperature_float > temp_cool_alert and temperature_float <= temp_mild_alert %}
{% set temperature_color = 'rgba(0, 102, 255, 0.8)' %}
{% elif temperature_float > temp_chilly_alert and temperature_float <= temp_cool_alert %}
{% set temperature_color = 'rgba(0, 102, 255, 0.8)' %}
{% elif temperature_float > temp_cold_alert and temperature_float <= temp_chilly_alert %}
{% set temperature_color = 'rgba(0, 102, 255, 0.8)' %}
{% elif temperature_float > temp_frosty_alert and temperature_float <= temp_cold_alert %}
{% set temperature_color = 'rgba(0, 102, 255, 0.8)' %}
{% elif temperature_float < temp_frosty_alert %}
{% set temperature_color = 'rgba(0, 102, 255, 0.8)' %}
{% endif %}
{% endif %}
{# Apply gradient with spaces #}
radial-gradient(circle, {{ humidity_color }} 0%, black, {{ temperature_color }} 70%) !important;
{% endmacro %}
{# SAC Card Element Floating Circle #}
{% macro card_mod_floating_circle_movement_and_color(humidity_entity, temperature_entity) %}
{% set humidity_state = states(humidity_entity) %}
{% set temperature_state = states(temperature_entity) %}
{% set humidity_float = humidity_state | float(50) if humidity_state not in ['unknown', 'unavailable'] else 50 %}
{% set temperature_float = temperature_state | float(22) if temperature_state not in ['unknown', 'unavailable'] else 22 %}
{# Alert Levels and scaling factors #}
{% set temp_min = 15 %}
{% set temp_max = 35 %}
{% set temp_min_warning = 18 %}
{% set temp_max_warning = 26.4 %}
{% set humidity_min = 40 %}
{% set humidity_max = 60 %}
{# Scaling Map temp to 0% (bottom) → 100% (top) of the card #}
{% set temp_scaled = (((temperature_float - temp_min) * (100 - 0) / (temp_max - temp_min)) + 0) | round(1) %}
{% set temp_scaled = [0, temp_scaled, 100] | sort | join(' ') | regex_replace('^.*? (.*?) .*$', '\\1') %}
{# Check if the Floating Circle is outside Outer Ring Limits Temp or Inner Circle Comfort Zone Humidity #}
{% set outside_limits = (humidity_float < humidity_min) or (humidity_float > humidity_max) or (temperature_float < temp_min_warning) or (temperature_float > temp_max_warning) or (humidity_float == 50) or (temperature_float == 22.0) %}
{# Positioning the floating circle #}
left: {{ humidity_float + 0.5 }}%;
bottom: {{ temp_scaled }}%;
transition: bottom 0.8s ease-in-out, left 0.8s ease-in-out;
transform: translate(-50%, 50%);
{# Ensures the icon itself does NOT blink #}
ha-icon {
color: white !important;
}
{# Default state: Fully transparent #}
ha-card {
border-radius: 50%;
background: transparent !important;
position: relative;
aspect-ratio: 1 / 1;
width: 100%;
height: auto;
}
{# When outside limits, apply blinking red gradient #}
{% if outside_limits %}
ha-card::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
aspect-ratio: 1 / 1;
width: 100%;
height: 100%;
background: radial-gradient(circle,
rgba(255,0,0,0.8) 20%,
rgba(255,0,0,0.3) 50%,
rgba(255,0,0,0.1) 70%,
rgba(255,0,0,0) 100%
) !important;
animation: blink 1s infinite alternate;
}
{% endif %}
{# Define blinking animation #}
@keyframes blink {
0% { opacity: 1; }
100% { opacity: 0.3; }
}
{% endmacro %}
SENSOR CODE
- In your
configuration.yaml
file paste the followingtemplate:
sensors:
into your configuration to make a single card. - Ensure you enter your Temperature and Humidity Sensors. Wind Speed Optional for Australian Apparent Temperature
- Any sensors that start with
sensor.sac
are calculated in the Macro. - Rename i.e.
living_room
to suit your needs
SENSOR CODE
template:
- sensor:
# Template Australian Apparent Temperature - Wind Speed Optional (km/h) - Utilising custom_templates/macros.jinja
- name: "sac_feels_like_temperature_living_room"
unique_id: 4dc577f3-7d28-4083-a010-ac3825fd6fd1
unit_of_measurement: "°C"
icon: mdi:thermometer
state: >
{% from 'sac_macros.jinja' import calculate_apparent_temperature %}
{{ calculate_apparent_temperature('sensor.insert_temperature', 'sensor.insert_humidity','sensor.insert_wind_speed') }}
# Template Dew Point Sensors - Utilising custom_templates/macros.jinja
- name: "dewpoint_living_room"
unique_id: c5e921de-47d2-4338-9158-8097911df43e
unit_of_measurement: "°C"
icon: mdi:thermometer-water
state: >
{% from 'sac_macros.jinja' import calculate_dew_point %}
{{ calculate_dew_point('sensor.insert_temperature', 'sensor.insert_humidity') }}
# Template Simple Air Comfort Card - Dewpoint Colour - Outer Ring Limits - Living Room
- name: "sac_dewpoint_colour_living_room"
unique_id: c6639b18-ac02-441f-badd-815c6c810254
state: >-
{% from 'sac_macros.jinja' import calculate_dewpoint_colour_outer_ring_limits %}
{{ calculate_dewpoint_colour_outer_ring_limits('sensor.sac_text_dewpoint_comfort_living_room') }}
# Template Simple Air Comfort Card - Alert Colour - Inner Circle - Living Room
- name: "sac_inner_circle_alert_colour_living_room"
unique_id: a3c9d6d1-e51d-450b-a61c-1f7d9cc7baeb
state: >-
{% from 'sac_macros.jinja' import inner_circle_comfort_zone_alert_colour %}
{{ inner_circle_comfort_zone_alert_colour('sensor.air_conditioning_humidity', 'air_conditioning_temperature') }}
# Template Simple Air Comfort Card - Temperature Colour - Picture Elements Card Background - Living Room
- name: "sac_temperature_colour_living_room"
unique_id: dc6c834b-f775-4b36-a2f3-d43356632cc6
state: >-
{% from 'sac_macros.jinja' import calculate_temperature_colour_card_background %}
{{ calculate_temperature_colour_card_background('sensor.sac_text_temperature_comfort_living_room') }}
# Template Simple Air Comfort Card - Text Dewpoint Comfort - Living Room
- name: "sac_text_dewpoint_comfort_living_room"
unique_id: e8b76541-7fe7-407e-b53d-f012a3d6152b
state: >-
{% from 'sac_macros.jinja' import calculate_text_dewpoint_comfort %}
{{ calculate_text_dewpoint_comfort('sensor.dewpoint_living_room') }}
# Template Simple Air Comfort Card - Text Temperature Comfort - Living Room
- name: "sac_text_temperature_comfort_living_room"
unique_id: 5e2b7728-1630-4d3f-b511-04d48bf76cd4
state: >-
{% from 'sac_macros.jinja' import calculate_text_temperature_comfort %}
{{ calculate_text_temperature_comfort('sensor.air_conditioning_temperature') }}
# Template Simple Air Comfort Card - Text Humidity Comfort - Living Room
- name: "sac_text_humidity_comfort_living_room"
unique_id: f299c759-e50c-4f9f-a775-b99734dab132
state: >-
{% from 'sac_macros.jinja' import calculate_text_humidity_comfort %}
{{ calculate_text_humidity_comfort('sensor.air_conditioning_humidity') }}
Thanks @LiQuid_cOOled for the input and @vajdum, may be of interest to you.
FINALLY V5.1 SIMPLE AIR COMFORT CARD
- Paste the following code into your lovelace dashboard view
- Only thing that needs to be changed is the word
living_room
to suit your needs, also add your temperature and humidity sensors. - Any sensors that start with
sensor.sac
are calculated in the Macro.
SIMPLE AIR COMFORT CARD YAML
- type: picture-elements
image: >-
local/community/simple-air-comfort-card/sac_background_overlay.svg
card_mod:
style: |
ha-card {
--ha-card-background: {{states('sensor.sac_temperature_colour_living_room')}}
--ha-card-border-width: 0px !important;
--ha-card-border-radius: 5px !important;
--box-shadow: none !important;
}
elements:
- type: custom:button-card
name: Card Title
label: Living Room
show_name: false
show_label: true
style:
left: 50%
top: 5%
width: 100%
transform: translate(-50%, -50%) scale(0.7, 0.7)
styles:
card:
- background: transparent
- border-color: transparent
label:
- color: silver
- type: custom:button-card
name: Text Dew Point Comfort - Living Room
entity: sensor.sac_text_dewpoint_comfort_living_room
label: >-
configuration.yaml template text sensor, calculated
from sac_macro.jinja
show_state: true
show_name: false
show_label: false
show_icon: false
style:
right: '-50%'
top: 14%
width: 100%
transform: translate(-50%, -50%) scale(0.95, 0.95)
styles:
card:
- background: transparent
- border-color: transparent
state:
- font-weight: bold
- type: custom:button-card
name: Sensor 1 - Dewpoint - Living Room
entity: sensor.dewpoint_living_room
label: >-
configuration.yaml template dewpoint sensor,
calculated from sac_macro.jinja
icon: mdi:water-thermometer-outline
show_state: true
show_name: false
show_icon: true
show_label: false
style:
left: 20%
top: 25%
width: 50%
transform: translate(-50%, -50%) scale(0.6, 0.6)
styles:
card:
- background: transparent
- border-color: transparent
icon:
- color: auto
- type: custom:button-card
name: Sensor 2 - Feels Like - Living Room
entity: sensor.living_room_feels_like_temperature
icon: tc:thermal-perception-alternative
show_state: true
show_name: false
show_icon: true
style:
left: 80%
top: 25%
width: 50%
transform: translate(-50%, -50%) scale(0.6, 0.6)
styles:
card:
- background: transparent
- border-color: transparent
icon:
- color: auto
- type: custom:button-card
name: Sensor 3 - Temperature - Living Room
entity: sensor.air_conditioning_temperature
show_state: true
show_name: false
show_icon: true
style:
left: 20%
top: 75%
width: 50%
transform: translate(-50%, -50%) scale(0.8, 0.8)
styles:
card:
- background: transparent
- border-color: transparent
icon:
- color: auto
- type: custom:button-card
name: Sensor 4 - Humidity - Living Room
entity: sensor.air_conditioning_humidity
show_state: true
show_name: false
show_icon: true
style:
left: 80%
top: 75%
width: 50%
transform: translate(-50%, -50%) scale(0.8, 0.8)
styles:
card:
- background: transparent
- border-color: transparent
icon:
- color: auto
- type: custom:button-card
name: Text Temperature Comfort Sensor 3 - Living Room
entity: sensor.sac_text_temperature_comfort_living_room
label: >-
configuration.yaml template text sensor, calculated
from sac_macro.jinja
show_state: true
show_name: false
show_label: false
show_icon: false
style:
left: 20%
top: 92%
width: 50%
transform: translate(-50%, -50%) scale(0.9, 0.9)
styles:
card:
- background: transparent
- border-color: transparent
- type: custom:button-card
name: Text Humidity Comfort Sensor 4 - Living Room
entity: sensor.sac_text_humidity_comfort_living_room
label: >-
configuration.yaml template text sensor, calculated
from sac_macro.jinja
show_state: true
show_name: false
show_label: false
show_icon: false
style:
left: 80%
top: 92%
width: 50%
transform: translate(-50%, -50%) scale(0.9, 0.9)
styles:
card:
- background: transparent
- border-color: transparent
- type: custom:button-card
name: Outer Ring Limits
show_name: false
show_icon: false
aspect_ratio: 1/1
style:
right: 4.5%
top: 50%
height: 45%
width: 45%
styles:
card:
- border-radius: 50%
- border-width: 2.5px
- border-color: rgba(255,255,255,1)
card_mod:
style: |
ha-card {
--ha-card-background: {{states('sensor.sac_dewpoint_colour_living_room')}}
}
- type: custom:button-card
name: Inner Circle Comfort Zone
show_name: false
show_icon: false
aspect_ratio: 1/1
style:
right: 28.5%
top: 50%
height: 21%
width: 21%
styles:
card:
- border-radius: 50%
- border-width: 0px
card_mod:
style: |
ha-card {
--ha-card-background: {{states('sensor.sac_inner_circle_alert_colour_living_room')}}
}
- type: custom:button-card
name: Floating Circle
icon: mdi:circle
show_name: false
show_icon: true
style:
width: 15%
height: 15%
styles:
card:
- background: transparent
- border-color: transparent
card_mod:
style: |
:host {
{% from 'sac_macros.jinja' import card_mod_floating_circle_movement_and_color %}
{{ card_mod_floating_circle_movement_and_color('sensor.air_conditioning_humidity', 'sensor.air_conditioning_temperature') }}
}
- type: custom:button-card
label: Warm
show_label: true
style:
right: 0%
top: 22%
width: 50%
transform: translate(-50%, -50%) scale(0.7, 0.7)
styles:
label:
- color: grey
card:
- background: transparent
- border-color: transparent
- type: custom:button-card
label: Cold
show_label: true
style:
right: 0%
top: 79%
width: 50%
transform: translate(-50%, -50%) scale(0.7, 0.7)
styles:
label:
- color: grey
card:
- background: transparent
- border-color: transparent
- type: custom:button-card
label: Dry
show_label: true
style:
left: 22%
top: 50%
width: 20%
transform: translate(-50%, -50%) scale(0.7, 0.7)
styles:
label:
- color: grey
- writing-mode: vertical-rl
- transform: rotate(180deg)
card:
- background: transparent
- border-color: transparent
- type: custom:button-card
label: Humid
show_label: true
style:
left: 79%
top: 50%
width: 20%
transform: translate(-50%, -50%) scale(0.7, 0.7)
styles:
label:
- color: grey
- writing-mode: vertical-rl
card:
- background: transparent
- border-color: transparent
Thank you for a great card!
Found minor bug in all versions.
Feels like sensor present in jinja template and ui, but not in the sensors template block. Needs to be added something like
# Template Feels Like Sensors - Utilising custom_templates/macros.jinja
- name: "bedroom_feels_like_temperature"
unique_id: c5e921de-47d2-4338-9158-8097911df44f
unit_of_measurement: "°C"
icon: mdi:home-thermometer
state: >
{% from 'sac_macros.jinja' import calculate_apparent_temperature %}
{{ calculate_apparent_temperature('sensor.YOUR_SENSOR_temperature', 'sensor.YOUR_SENSOR_humidity') }}
I will look at that tomorrow and rectify, must have forgot to paste as it sits in a slightly different spot in my configuration.yaml. @Crickus Thanks for the feedback and pleased you liked the card.
EDIT: Sensor Template Added to V5.1 Above thanks @Crickus
Wind Speed is an optional sensor you can add for the macro to calculate from. good for outdoor locations
# Template Australian Apparent Temperature - Wind Speed Optional (km/h) - Utilising custom_templates/macros.jinja
- name: "sac_feels_like_temperature_living_room"
unique_id: 4dc577f3-7d28-4083-a010-ac3825fd6fd1
unit_of_measurement: "°C"
icon: mdi:thermometer
state: >
{% from 'sac_macros.jinja' import calculate_apparent_temperature %}
{{ calculate_apparent_temperature('sensor.insert_temperature', 'sensor.insert_humidity','sensor.insert_wind_speed') }}