Skip to content

Instantly share code, notes, and snippets.

@handcoding
Last active April 27, 2024 17:02
Show Gist options
  • Star 24 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save handcoding/c2fe8a9e895262cefbee886e0019cada to your computer and use it in GitHub Desktop.
Save handcoding/c2fe8a9e895262cefbee886e0019cada to your computer and use it in GitHub Desktop.
This script for Home Assistant will fade a lamp over time with your choice of easing, including varieties of ease-in, ease-out, and ease-in-out.
alias: Ashley’s Light Fader
description: >
Fades a lamp over time. If you have any questions or comments about this
script, feel free to tweet Ashley Bischoff at @FriendlyAshley. Released under
the Apache 2.0 license. (v2.0)
fields:
light:
name: 💡 Light
description: entity_id of the lamp.
selector:
entity:
domain: light
example: light.kitchen
required: true
lampBrightnessScale:
name: The lamp’s internal brightness scale
description: >
Most lamps seem to internally use a 0 to 255 brightness scale, but some
lamps internally use a 0% to 100% brightness scale. Either of these
settings will still fade the lamp, but if you happen to match this setting
to the lamp’s internal brightness scale, the resulting fade may be
smoother. (If you’re not sure, you can just leave this as is.)
advanced: true
required: true
selector:
select:
options:
- label: 0% to 100%
value: zeroToOneHundred
- label: 0 to 255
value: zeroToTwoFiftyFive
default: zeroToTwoFiftyFive
transitionTime:
name: ⏱ Fade time
description: Fade duration.
selector:
duration: null
required: true
easingTypeInput:
name: 📉 Easing type
description: >-
The easing function that you’d like the fade to use. As a starting
point—you can’t go wrong with any of the “Ease-In-Out X” easings as those
will always look pretty good whenever you’re fading between two nonzero
brightness values. As well, the “Ease-Out X” easings often tend to look
good if you might be fading up very quickly from zero to another
brightness, and the “Ease-In X” easings are mostly only included for
completeness as those tend to only look good if you might be fading down
to zero very quickly. (See also https://easings.net for visual demos of
each of these easing types.)
selector:
select:
mode: list
options:
- label: Try to automatically select the easing type
value: auto
- label: Ease-In-Out Sine [a good all-rounder]
value: easeInOutSine
- label: Ease-In-Out Quad
value: easeInOutQuad
- label: Ease-In-Out Cubic
value: easeInOutCubic
- label: Ease-In-Out Quart
value: easeInOutQuart
- label: Ease-Out Sine
value: easeOutSine
- label: Ease-Out Quad
value: easeOutCubic
- label: Ease-Out Cubic
value: easeOutCubic
- label: Ease-Out Quart
value: easeOutQuart
- label: Ease-In Sine
value: easeInSine
- label: Ease-In Quad
value: easeInCubic
- label: Ease-In Cubic
value: easeInCubic
- label: Ease-In Quart
value: easeInQuart
- label: Linear [somewhat unnatural to the human eye; not recommended]
value: linear
default: auto
required: true
endBrightnessPercent:
name: End brightness level
description: Percentage from 0 to 100 representing the final brightness level.
selector:
number:
min: 0
max: 100
step: 1
mode: slider
unit_of_measurement: "%"
default: 50
example: "50"
required: true
endBrightnessEntity:
name: (optional) Use an entity instead for the end-brightness value?
description: >-
You can optionally have the script ignore the end-brightness value above
and instead use the numeric value of anonther entity that you select here,
such as an input-number helper, an input-select helper, an input-text
helper, or a numeric sensor.
selector:
entity:
domain:
- input_number
- input_select
- input_text
- sensor
example: input_number.dining_room_entertaining_level
required: false
advanced: true
endBrightnessEntityScale:
name: The end-brightness entity’s brightness scale (if used)
description: >-
If you enable the “use an entity for the end-brightness value instead”
option, select here whether your chosen entity represents brightness with
a 0% to 100% scale or a 0 to 255 scale. (Note—in either case, this script
will expect that entity to solely have an integer value without any
nonnumeric characters such as “%”.)
advanced: true
selector:
select:
options:
- label: 0% to 100%
value: zeroToOneHundred
- label: 0 to 255
value: zeroToTwoFiftyFive
default: zeroToOneHundred
required: true
endColorTemperatureKelvin:
name: 🎨 (optional) End color temperature (in Kelvin)
description: >-
Color temperature from 2000 K to 6500 K representing the final color
temperature.
selector:
number:
min: 2000
max: 6500
step: 50
mode: slider
unit_of_measurement: °K
example: "2700"
required: false
endColorTemperatureKelvinEntity:
name: (optional) Use an entity instead for the ending Kelvin value?
description: >-
You can optionally have the script ignore the end-color-temperature value
above and instead use the numeric value of anonther entity that you select
here, such as an input-number helper, an input-select helper, an
input-text helper, or a numeric sensor.
selector:
entity:
domain:
- input_number
- input_select
- input_text
- sensor
example: input_number.dining_room_color_temperature
required: false
advanced: true
autoCancelThreshold:
name: 🚫 (optional) Brightness-change threshold that auto-cancels the fade
description: >-
You can optionally have the script automatically cancel its fade if the
lamp’s brightness were to be manually changed by a certain amount. For
example, let’s suppose that you were to set this value to 5% and then you
were to run this script. If there comes a point within the fade where this
script is expecting the lamp to be at, say, 22% brightness—but you’ve just
manually set that lamp to 30% brightness—this script will automatically
cancel its fade since that 8% difference is >= 5%. Note—if you use this,
Ashley doesn’t recommend setting this to anything less than about 3;
that’s just because it can be normal for there to be an occasional
difference of 1 or 2 since not all lamps instantly reflect newly assigned
brightness values due to processing lag and other factors. In Ashley’s
home, she personally uses a value of about 5 for this.
selector:
number:
min: 2
max: 100
step: 1
mode: slider
unit_of_measurement: "%"
default: 10
example: "10"
required: false
shouldStopIfTheLampIsTurnedOffDuringTheFade:
name: ⤵️ Cancel the fade if the lamp is turned off during the fade?
description: >-
By default, the script will automatically disengage if the lamp is turned
off during the fade. But if you’d like to, you can also disable that
behavior with this switch. (And don’t worry—this feature is smart enough
to not automatically cancel the fade at points when the lamp’s intended
brightness might be zero, such as if the script were to be fading down to
zero or fading up from zero.)
selector:
boolean: null
advanced: false
required: true
default: true
stopEntity:
name: 🛑 (optional) Stop if a certain entity is turned on during the fade?
description: >-
You can optionally have the script keep an eye on an input boolean or a
binary sensor or a light. And if that entity is then turned on during the
fade, the script will automatically stop. So for example, if you create a
“Stop Everything” input boolean, and if you set that entity here, you can
stop your fade at any time by turning on that “Stop Everything” entity.
selector:
entity:
domain:
- input_boolean
- binary_sensor
- light
- switch
example: input_boolean.stop_everything
required: false
advanced: true
shouldResetTheStopEntityToOffAtStart:
name: (optional) Reset that “stop” entity to off just before starting the fade?
description: >-
If you make use of the stop entity (above), you can also optionally have
the script automatically reset that entity to “off” at the start of the
fade. (By default, the script won’t change the value of the stop entity.)
selector:
boolean: null
advanced: true
required: true
default: false
shouldInvertTheValueOfTheStopEntity:
name: (optional) Stop only if the “stop” entity is instead turned OFF?
description: >-
If you make use of the stop entity (above), you can optionally have the
script automatically stop only if that entity is turned OFF during the
fade.
selector:
boolean: null
advanced: true
required: true
default: false
minimumStepDelayInMilliseconds:
name: Minimum delay per step
description: >-
The minimum delay between sending each brightness command. Some lamps only
accept commands every X milliseconds—so while you can probably leave this
as is, if by chance your lamp were to behave strangely, you might try
bumping up this number by another ten or twenty milliseconds.
advanced: true
selector:
number:
min: 50
max: 1000
step: 10
mode: slider
unit_of_measurement: ms
default: 100
example: "100"
shouldTryToUseNativeLampTransitionsToo:
name: 🧪 (experimental) If available, use the lamp's native transitions too?
description: >-
If this is enabled and if the lamp natively supports transitions, the
script will make use of the lamp’s native transition effect when moving between
brightness steps or color steps if those steps are very gradually spaced.
When enabled, this has the possibility of offering even smoother fades.
And if the lamp doesn’t happen to support the transition effect in the
first place, this feature will automatically disengage. (And while Ashley
feels comfortable using this feature in her own house, this feature isn’t
as thoroughly tested as the script’s other features, so this feature is
considered experimental for now.)
selector:
boolean: null
advanced: true
required: true
default: false
isDebugMode:
name: 🐛 Enable debugging mode?
description: >-
If this is enabled, the script will output status messages to your Home
Assistant log along the way. Unless something were to be acting weirdly,
you can leave this off.
selector:
boolean: null
advanced: true
required: true
default: false
sequence:
- variables:
lightFriendlyName: "{{ state_attr(light, 'friendly_name') }}"
startTimestamp: "{{ as_timestamp(now()) }}"
fadeTimeInSeconds: >
{{ ((transitionTime.hours | int) * 60 * 60) + ((transitionTime.minutes |
int) * 60) + (transitionTime.seconds | int) }}
endTimestamp: "{{ startTimestamp + fadeTimeInSeconds }}"
fadeTimeInMilliseconds: "{{ fadeTimeInSeconds * 1000 }}"
shouldIgnoreTheEndBrightnessValueAndUseAnEntityForTheEndBrightnessInstead: >
{% if (endBrightnessEntity is defined) and
(has_value(endBrightnessEntity)) %}
{{ true }}
{% else %}
{{ false }}
{% endif %}
shouldIgnoreTheEndColorTemperatureValueAndUseAnEntityForTheEndColorTemperatureInstead: >
{% if (endColorTemperatureKelvinEntity is defined) and
(has_value(endColorTemperatureKelvinEntity)) %}
{{ true }}
{% else %}
{{ false }}
{% endif %}
isStopEntityEnabled: |
{% if (stopEntity is defined) and (has_value(stopEntity)) %}
{{ true }}
{% else %}
{{ false }}
{% endif %}
isStopEntityToggleable: |
{% if isStopEntityEnabled %}
{% set stopEntityDomain = states[stopEntity].domain %}
{% if stopEntityDomain == "binary_sensor" %}
{{ false }}
{% else %}
{## branch for stopEntityDomain being an input_boolean or a light or a switch ##}
{{ true }}
{% endif %}
{% else %}
{{ false }}
{% endif %}
stopEntityFriendlyName: |
{% if isStopEntityEnabled %}
{{ state_attr(stopEntity, 'friendly_name') }}
{% else %}
{{ "" }}
{% endif %}
minColorTemperatureKelvin: >
{## init ##} {% set minColorTemperature = -1 %}
{% set minColorTemperatureValue = state_attr(light,
'min_color_temp_kelvin') %} {% if minColorTemperatureValue %}
{% if is_number(minColorTemperatureValue) %}
{% set minColorTemperature = minColorTemperatureValue | int %}
{% endif %}
{% endif %} {{ minColorTemperature }}
maxColorTemperatureKelvin: >
{## init ##} {% set maxColorTemperature = -1 %}
{% set maxColorTemperatureValue = state_attr(light,
'max_color_temp_kelvin') %} {% if maxColorTemperatureValue %}
{% if is_number(maxColorTemperatureValue) %}
{% set maxColorTemperature = maxColorTemperatureValue | int %}
{% endif %}
{% endif %} {{ maxColorTemperature }}
doesLampSupportColorTemperatureKelvin: |
{% if ((minColorTemperatureKelvin | int) > 0) and
((maxColorTemperatureKelvin | int)) > 0 %}
{{ true }}
{% else %}
{{ false }}
{% endif %}
doesLampSupportTransitions: >+
{% set supportedFeatures = state_attr(light, 'supported_features') | int
%}
{## Bitfield of features supported by the light entity ##} {##
SUPPORT_BRIGHTNESS = 1 ##} {## SUPPORT_COLOR_TEMP = 2 ##} {##
SUPPORT_EFFECT = 4 ##} {## SUPPORT_FLASH = 8 ##} {## SUPPORT_COLOR = 16
##} {## SUPPORT_TRANSITION = 32 ##} {## SUPPORT_WHITE_VALUE = 128 ##}
{## via:
https://github.com/home-assistant/core/blob/787faaa508cf83ca4f850ee7000ad17eade915aa/homeassistant/components/light/__init__.py#L39
##}
{% if supportedFeatures >= 128 %}
{% set supportedFeatures = supportedFeatures - 128 %}
{% endif %}
{% if supportedFeatures >= 32 %}
{{ true }}
{% else %}
{{ false }}
{% endif %}
endColorTemperature: >
{% if
shouldIgnoreTheEndColorTemperatureValueAndUseAnEntityForTheEndColorTemperatureInstead
%}
{% set entityColorTemperatureValue = states(endColorTemperatureKelvinEntity) | round (0) %}
{% set endColorTemperatureKelvinValue = entityColorTemperatureValue | int %}
{% if endColorTemperatureKelvinValue > (maxColorTemperatureKelvin | int
) %}
{% set endColorTemperatureKelvinValue = maxColorTemperatureKelvin |int %}
{% endif %}
{% if endColorTemperatureKelvinValue < (minColorTemperatureKelvin | int
)%}
{% set endColorTemperatureKelvinValue = minColorTemperatureKelvin | int %}
{% endif %}
{% else %}
{## branch for shouldIgnoreTheEndColorTemperatureValueAndUseAnEntityForTheEndColorTemperatureInstead being off ##}
{% if (endColorTemperatureKelvin is defined) and endColorTemperatureKelvin %}
{% set endColorTemperatureKelvinValue = endColorTemperatureKelvin | round(0) %}
{% else %}
{% set endColorTemperatureKelvinValue = 0 %}
{% endif %}
{% endif %}
{{ endColorTemperatureKelvinValue }}
isColorFadeRequested: |
{% if (endColorTemperature |int) > 0 %}
{{ true }}
{% else %}
{{ false }}
{% endif %}
endBrightness: |
{% if shouldIgnoreTheEndBrightnessValueAndUseAnEntityForTheEndBrightnessInstead %}
{% set entityBrightnessValue = states(endBrightnessEntity) | round (0) %}
{% if (endBrightnessEntityScale == lampBrightnessScale) %}
{% set endBrightness = entityBrightnessValue %}
{% elif (lampBrightnessScale == "zeroToTwoFiftyFive") and (endBrightnessEntityScale == "zeroToOneHundred") %}
{% set endBrightness = (entityBrightnessValue * 2.55) | round(0) %}
{% elif (lampBrightnessScale == "zeroToOneHundred") and (endBrightnessEntityScale == "zeroToTwoFiftyFive") %}
{% set endBrightness = (entityBrightnessValue / 2.55) | round(0) %}
{% endif %}
{% else %}
{## branch for using the brightness selector's value rather than an entity's brightness value ##}
{% if lampBrightnessScale == "zeroToOneHundred" %}
{% set endBrightness = endBrightnessPercent %}
{% else %}
{## lampBrightnessScale == "zeroToTwoFiftyFive" ##}
{% if endBrightnessPercent == 1 %}
{## special case to force the endBrightness to 1/255 if the user enters "1%" by inferring that the user is looking to set the lamp to its lowest possible brightness ##}
{% set endBrightness = 1 %}
{% else %}
{% set endBrightness = (endBrightnessPercent * 2.55) | round(0) %}
{% endif %}
{% endif %}
{% endif %}
{{ endBrightness }}
startBrightness: |
{% set rawLightLevel = state_attr(light, 'brightness') %}
{## If a light is off, its brightness will return "None"? So first check if there's a valid brightness before setting the value ##}
{% if rawLightLevel %}
{% set currentLightLevel = rawLightLevel | int %}
{% else %}
{% set currentLightLevel = 0 %}
{% endif %}
{% if lampBrightnessScale == "zeroToOneHundred" %}
{% set currentLightLevel = (currentLightLevel / 2.55) | round(0) %}
{% endif %}
{## This next part, which nudges the starting level from 0 to 1, is necessary in cases
where there’s a color fade requested but the starting brightness level is 0.
And that’s because when a light is at 0, Home Assistant doesn’t know that light's Kelvin color. So the light first needs to be nudged toward 1 just so that this script can see what it’s
starting Kelvin color is. ##}
{% if (currentLightLevel == 0) and (endBrightness > currentLightLevel) and isColorFadeRequested %}
{% set currentLightLevel = 1 %}
{% endif %}
{{ currentLightLevel }}
brightnessSpan: "{{ endBrightness - startBrightness }}"
absoluteBrightnessSpan: "{{ brightnessSpan | abs }}"
shouldAutoCancelTheFadeIfTheLampBrightnessIsManuallyChanged: >
{% if (autoCancelThreshold is defined) and
(is_number(autoCancelThreshold)) %}
{{ true }}
{% else %}
{{ false }}
{% endif %}
normalizedAutoCancelThreshold: |
{% if not shouldAutoCancelTheFadeIfTheLampBrightnessIsManuallyChanged %}
{## exit early if shouldAutoCancelTheFadeIfTheLampBrightnessIsManuallyChanged isn’t even enabled ##}
{{ 255 }}
{% elif (lampBrightnessScale == "zeroToTwoFiftyFive") %}
{{ (autoCancelThreshold * 2.55) | round (0) }}
{% else %}
{{ autoCancelThreshold }}
{% endif %}
expectedBrightness: "{{ startBrightness }}"
- if:
- condition: template
value_template: >
{{ isStopEntityEnabled and isStopEntityToggleable and
shouldResetTheStopEntityToOffAtStart }}
then:
- service: homeassistant.turn_off
data: {}
target:
entity_id: "{{ stopEntity }}"
- if:
- condition: template
value_template: |
{## init ##} {% set shouldStop = false %} {% if isStopEntityEnabled %}
{% if (shouldInvertTheValueOfTheStopEntity is defined) and shouldInvertTheValueOfTheStopEntity %}
{% if not bool(states(stopEntity), false) %}
{% set shouldStop = true %}
{% endif %}
{% else %}
{% if bool(states(stopEntity), false) %}
{% set shouldStop = true %}
{% endif %}
{% endif %}
{% endif %} {{ shouldStop }}
then:
- if:
- condition: template
value_template: >
{{ (shouldInvertTheValueOfTheStopEntity is defined) and
shouldInvertTheValueOfTheStopEntity }}
then:
- variables:
stopMessage: >
{% set stopMessage = "Stopped Ashley’s Light Fader because " +
(stopEntityFriendlyName | string) + " is off." %} {{ stopMessage
}}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: |
{{ stopMessage }}
level: warning
- stop: |
{{ stopMessage }}
else:
- variables:
stopMessage: >
{% set stopMessage = "Stopped Ashley’s Light Fader because " +
(stopEntityFriendlyName | string) + " is on." %} {{ stopMessage
}}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: |
{{ stopMessage }}
level: warning
- stop: |
{{ stopMessage }}
- variables:
timestampBeforeServiceCall: "{{ as_timestamp(now()) }}"
- if:
- condition: template
value_template: |
{{ (lampBrightnessScale == "zeroToTwoFiftyFive") }}
then:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness: "{{ expectedBrightness }}"
else:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness_pct: "{{ expectedBrightness }}"
- variables:
processingDelayInMilliseconds: "{{ (as_timestamp(now()) - timestampBeforeServiceCall) * 1000 }}"
easingType: |
{% if "auto" in easingTypeInput %}
{% if (startBrightness == 0) and (fadeTimeInSeconds <= 20) %}
{{ "easeOutCubic" }}
{% elif (startBrightness == 0) and (fadeTimeInSeconds <= 55) %}
{{ "easeOutQuad" }}
{% elif (endBrightness == 0) and (fadeTimeInSeconds <= 20) %}
{{ "easeInCubic" }}
{% elif (endBrightness == 0) and (fadeTimeInSeconds <= 55) %}
{{ "easeInQuad" }}
{% else %}
{{ "easeInOutSine" }}
{% endif %}
{% else %}
{{ easingTypeInput }}
{% endif %}
isLampCurrentColorDefinedUsingKelvin: |+
{% set rawColorTemperature = state_attr(light, 'color_temp_kelvin') %}
{## If a light is off or if its color temperature is defined using a non-Kelvin color system,
its color temperature will return "None"? So first check if there's a valid color temperature ##}
{% if rawColorTemperature %}
{{ true }}
{% else %}
{{ false }}
{% endif %}
startColorTemperature: >+
{## init ##}
{% set currentColorTemperature = -1 %}
{% set rawColorTemperature = state_attr(light, 'color_temp_kelvin') %}
{## If a light is off or if its color temperature is defined using a
non-Kelvin color system,
its color temperature will return "None"? So first check if there's a valid color temperature ##}
{% if rawColorTemperature %}
{% if is_number(rawColorTemperature) %}
{% set currentColorTemperature = rawColorTemperature | int %}
{% endif %}
{% endif %}
{{ currentColorTemperature }}
colorTemperatureSpan: |
{% if doesLampSupportColorTemperatureKelvin %}
{{ (endColorTemperature | int) - (startColorTemperature | int) }}
{% else %}
{{ 0 }}
{% endif %}
absoluteColorTemperatureSpan: "{{ colorTemperatureSpan | int | abs }}"
isBrightnessFadeEnabled: |
{% if (absoluteBrightnessSpan | int) > 0 %}
{{ true }}
{% else %}
{{ false }}
{% endif %}
isColorFadeEnabled: >
{% if isColorFadeRequested and doesLampSupportColorTemperatureKelvin and
((absoluteColorTemperatureSpan | int) > 0) %}
{{ true }}
{% else %}
{{ false }}
{% endif %}
remainingTimeInMilliseconds: |
{% set nowTimestamp = as_timestamp(now()) %}
{{ (endTimestamp - nowTimestamp) * 1000 }}
delayInMilliseconds: >
{## init ##}
{% set frameMultiplicationFactor = 1 %}
{% if "Circ" in easingType %}
{## Four as many frames for Circ-type easings ##}
{## set idealDelay = (idealDelay / 4) | round(0) ##}
{% set frameMultiplicationFactor = 3 %}
{% elif ("Cubic" in easingType) or ("Quart" in easingType) %}
{## Three as many frames for Cubic-type or Quart-type easings ##}
{## set idealDelay = (idealDelay / 3) | round(0) ##}
{% set frameMultiplicationFactor = 2 %}
{% elif "ease" in easingType %}
{## Twice as many frames for other easing types ##}
{## set idealDelay = (idealDelay / 1.5) | round(0) ##}
{% set frameMultiplicationFactor = 1.2 %}
{% endif %}
{% if isBrightnessFadeEnabled %}
{% set brightnessFramesCount = (frameMultiplicationFactor * absoluteBrightnessSpan) | round(0) %}
{% set totalExpectedRemainingBrightnessFadeProcessingDelay = processingDelayInMilliseconds * brightnessFramesCount %}
{% set idealBrightnessFadeDelay = ((remainingTimeInMilliseconds - totalExpectedRemainingBrightnessFadeProcessingDelay) / brightnessFramesCount) | round(0) %}
{% else %}
{% set idealBrightnessFadeDelay = 0 %}
{% endif %}
{% if isColorFadeEnabled %}
{## The division by 25 below is working from the idea that you’d want the color fade
to progress at least every 25°K, such as 2,000 K, 2,025 K, 2,050 K, and so on ##}
{% set colorFramesCount = (frameMultiplicationFactor * (absoluteColorTemperatureSpan / 25)) | round(0) %}
{% set totalExpectedRemainingColorFadeProcessingDelay = (processingDelayInMilliseconds * colorFramesCount) | round(0) %}
{% set idealColorFadeDelay = ((remainingTimeInMilliseconds - totalExpectedRemainingColorFadeProcessingDelay) / colorFramesCount ) | round(0) %}
{% else %}
{% set idealColorFadeDelay = 0 %}
{% endif %}
{## init ##} {% set idealDelay = 0 %}
{## if both brightness-fade is enabled and color-fade is enabled, pick
the one with the lowest ideal delay ##}
{% if isBrightnessFadeEnabled and isColorFadeEnabled %}
{% if idealBrightnessFadeDelay < idealColorFadeDelay %}
{% set idealDelay = idealBrightnessFadeDelay %}
{% else %}
{% set idealDelay = idealColorFadeDelay %}
{% endif %}
{% elif isBrightnessFadeEnabled %}
{% set idealDelay = idealBrightnessFadeDelay %}
{% elif isColorFadeEnabled %}
{% set idealDelay = idealColorFadeDelay %}
{% endif %}
{## Make sure that the delay isn’t below the
minimumStepDelayInMilliseconds ##} {% if idealDelay <
minimumStepDelayInMilliseconds %}
{{ minimumStepDelayInMilliseconds }}
{% else %}
{{ idealDelay }}
{% endif %}
delayInSeconds: |
{{ (delayInMilliseconds | int) / 1000 }}
transitionTimeParameterInSeconds: >
{% set transitionTimeParameterInSeconds = ((delayInSeconds | float) *
0.9) | round(3) %}
{## set a ceiling on the transition time ##}
{% if transitionTimeParameterInSeconds > 10 %}
{% set transitionTimeParameterInSeconds = 10 %}
{% endif %}
{{ transitionTimeParameterInSeconds }}
minimumDelayInSecondsBeforeUsingNativeLampNativeTransitionsToo: |
{{ 1 }}
shouldUseNativeLampTransitionsToo: |
{% if
(
(shouldTryToUseNativeLampTransitionsToo is defined)
and shouldTryToUseNativeLampTransitionsToo
and doesLampSupportTransitions
and ((transitionTimeParameterInSeconds | float(0) ) >=
minimumDelayInSecondsBeforeUsingNativeLampNativeTransitionsToo | float(0) )
)
%}
{{ true }}
{% else %}
{{ false }}
{% endif %}
- if:
- condition: template
value_template: >
{{ ((absoluteBrightnessSpan | int) == 0) and not isColorFadeEnabled
}}
then:
- variables:
stopMessage: >
{% set stopMessage = "Stopped Ashley’s Light Fader because " +
(lightFriendlyName | string) + "’s starting brightness is the same
as its ending brightness." %} {{ stopMessage }}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: |
{{ stopMessage }}
level: warning
- stop: |
{{ stopMessage }}
- if:
- condition: template
value_template: >
{{ ((absoluteBrightnessSpan | int) == 0) and
((absoluteColorTemperatureSpan | int) == 0) and isColorFadeEnabled
}}
then:
- variables:
stopMessage: >
{% set stopMessage = "Stopped Ashley’s Light Fader because " +
(lightFriendlyName | string) + "’s starting brightness is the same
as its ending brightness and its starting color temperature is the
same as its ending color temperature." %} {{ stopMessage }}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: |
{{ stopMessage }}
level: warning
- stop: |
{{ stopMessage }}
- if:
- condition: template
value_template: >
{{ isColorFadeRequested and not doesLampSupportColorTemperatureKelvin
}}
then:
- variables:
stopMessage: >
{% set stopMessage = "Stopped Ashley’s Light Fader because a color
fade was requested for " + (lightFriendlyName | string) + ", but it
doesn’t seem to support Kelvin color temperatures. (You can look
into this by going into Developer Tools and checking that " +
(lightFriendlyName | string) + " has the defined attributes for
“min_color_temp_kelvin” and “max_color_temp_kelvin”.)" %} {{
stopMessage }}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: |
{{ stopMessage }}
level: warning
- stop: |
{{ stopMessage }}
- if:
- condition: template
value_template: >
{{ isColorFadeRequested and not isLampCurrentColorDefinedUsingKelvin
}}
then:
- variables:
stopMessage: >
{% set stopMessage = "Stopped Ashley’s Light Fader because a color
fade was requested for " + (lightFriendlyName | string) + ", but its
current color temperature doesn’t seem to be defined using Kelvin
units. (You can look into this by going into Developer Tools and
checking that " + (lightFriendlyName | string) + " has a defined
“color_temp_kelvin” attribute.)" %} {{ stopMessage }}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: |
{{ stopMessage }}
level: warning
- stop: |
{{ stopMessage }}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- if:
- condition: template
value_template: |
{{ isColorFadeEnabled }}
then:
- service: system_log.write
data_template:
message: >
{{ easingType }} easing type with {{ delayInMilliseconds | int
}} ms delay. remainingTimeInMilliseconds = {{
remainingTimeInMilliseconds | round(0) }},
absoluteColorTemperatureSpan = {{ absoluteColorTemperatureSpan
}}, and absoluteBrightnessSpan = {{ absoluteBrightnessSpan }}
level: warning
- service: system_log.write
data_template:
message: >
startBrightness = {{ startBrightness }}, endBrightness = {{
endBrightness }}, startColorTemperature = {{
startColorTemperature }}, endColorTemperature = {{
endColorTemperature }}, and processingDelayInMilliseconds = {{
processingDelayInMilliseconds | int }}
level: warning
else:
- service: system_log.write
data_template:
message: >
{{ easingType }} easing type with {{ delayInMilliseconds | int
}} ms delay. remainingTimeInMilliseconds = {{
remainingTimeInMilliseconds | round(0) }}, and
absoluteBrightnessSpan = {{ absoluteBrightnessSpan }}
level: warning
- service: system_log.write
data_template:
message: >
startBrightness = {{ startBrightness }}, endBrightness = {{
endBrightness }}, and processingDelayInMilliseconds = {{
processingDelayInMilliseconds | int }}
level: warning
- repeat:
sequence:
- variables:
percentageOfTimeCompleted: >
{% set nowTimestamp = as_timestamp(now()) %}
{% set percentageOfTimeCompleted = ((nowTimestamp -
startTimestamp) / fadeTimeInSeconds) %}
{% if (percentageOfTimeCompleted < 0) %}
{% set percentageOfTimeCompleted = 0 %}
{% elif (percentageOfTimeCompleted > 1) %}
{% set percentageOfTimeCompleted = 1 %}
{% endif %}
{{ percentageOfTimeCompleted }}
easingAdjustedPercentageCompleted: >
{% set percentageOfTimeCompleted = percentageOfTimeCompleted |
float(0) %} {% if easingType == "easeInSine" %}
{## https://easings.net/#easeInSine ##}
{{ 1 - cos((percentageOfTimeCompleted * pi) / 2) }}
{% elif easingType == "easeInQuad" %}
{## https://easings.net/#easeInQuad ##}
{{ percentageOfTimeCompleted * percentageOfTimeCompleted }}
{% elif easingType == "easeInCubic" %}
{## https://easings.net/#easeInCubic ##}
{{ percentageOfTimeCompleted * percentageOfTimeCompleted * percentageOfTimeCompleted }}
{% elif easingType == "easeInQuart" %}
{## https://easings.net/#easeInQuart ##}
{{ percentageOfTimeCompleted * percentageOfTimeCompleted * percentageOfTimeCompleted * percentageOfTimeCompleted }}
{% elif easingType == "easeOutSine" %}
{## https://easings.net/#easeOutSine ##}
{{ sin((percentageOfTimeCompleted * pi) / 2) }}
{% elif easingType == "easeOutQuad" %}
{## https://easings.net/#easeOutQuad ##}
{{ 1 - (1 - percentageOfTimeCompleted)* (1 - percentageOfTimeCompleted) }}
{% elif easingType == "easeOutCubic" %}
{## https://easings.net/#easeOutCubic ##}
{{ 1 - ((1 - percentageOfTimeCompleted) ** 3) }}
{% elif easingType == "easeOutQuart" %}
{## https://easings.net/#easeOutQuart ##}
{{ 1 - ((1 - percentageOfTimeCompleted) ** 4) }}
{% elif easingType == "easeInOutSine" %}
{## https://easings.net/#easeInOutSine ##}
{{ -1 * ((cos(pi * percentageOfTimeCompleted) - 1) / 2) }}
{% elif easingType == "easeInOutQuad" %}
{## https://easings.net/#easeInOutQuad ##}
{% if (percentageOfTimeCompleted < 0.5) %}
{{ 2 * percentageOfTimeCompleted * percentageOfTimeCompleted }}
{% else %}
{{ 1- (((-2 * percentageOfTimeCompleted + 2) ** 2) / 2) }}
{% endif %}
{% elif easingType == "easeInOutCubic" %}
{## https://easings.net/#easeInOutCubic ##}
{% if (percentageOfTimeCompleted < 0.5) %}
{{ 4 * percentageOfTimeCompleted * percentageOfTimeCompleted * percentageOfTimeCompleted }}
{% else %}
{{ 1- (((-2 * percentageOfTimeCompleted + 2) ** 3) / 2) }}
{% endif %}
{% elif easingType == "easeInOutQuart" %}
{## https://easings.net/#easeInOutQuart ##}
{% if (percentageOfTimeCompleted < 0.5) %}
{{ 8 * percentageOfTimeCompleted * percentageOfTimeCompleted * percentageOfTimeCompleted * percentageOfTimeCompleted }}
{% else %}
{{ 1 - (((-2 * percentageOfTimeCompleted + 2) ** 4) / 2) }}
{% endif %}
{% else %}
{## linear ##}
{{ percentageOfTimeCompleted }}
{% endif %}
expectedBrightness: |
{% if isBrightnessFadeEnabled %}
{% set startBrightness = startBrightness | int %}
{% set brightnessSpan = brightnessSpan | int %}
{% set easingAdjustedPercentageCompleted = easingAdjustedPercentageCompleted | float(0) %}
{% set calculatedBrightness = (startBrightness + (brightnessSpan * easingAdjustedPercentageCompleted)) | round(0) %}
{% if (calculatedBrightness < 0) %}
{% set calculatedBrightness = 0 %}
{% elif (calculatedBrightness > 255) %}
{% set calculatedBrightness = 255 %}
{% endif %}
{% if (endBrightness >= startBrightness) and (calculatedBrightness > endBrightness) %}
{% set calculatedBrightness = endBrightness %}
{% elif (endBrightness < startBrightness) and (calculatedBrightness < endBrightness) %}
{% set calculatedBrightness = endBrightness %}
{% endif %}
{% else %}
{## if isBrightnessFadeEnabled is false ##}
{% set calculatedBrightness = startBrightness %}
{% endif %}
{{ calculatedBrightness }}
linearExpectedBrightness: |
{% if isBrightnessFadeEnabled %}
{% set startBrightness = startBrightness | int %}
{% set brightnessSpan = brightnessSpan | int %}
{% set percentageOfTimeCompleted = percentageOfTimeCompleted | float(0) %}
{% set calculatedBrightness = (startBrightness + (brightnessSpan * percentageOfTimeCompleted)) | round(0) %}
{% if (calculatedBrightness < 0) %}
{% set calculatedBrightness = 0 %}
{% elif (calculatedBrightness > 255) %}
{% set calculatedBrightness = 255 %}
{% endif %}
{% if (endBrightness >= startBrightness) and (calculatedBrightness > endBrightness) %}
{% set calculatedBrightness = endBrightness %}
{% elif (endBrightness < startBrightness) and (calculatedBrightness < endBrightness) %}
{% set calculatedBrightness = endBrightness %}
{% endif %}
{% else %}
{## if isBrightnessFadeEnabled is false ##}
{% set calculatedBrightness = startBrightness %}
{% endif %}
{{ calculatedBrightness }}
currentBrightness: |+
{% if isBrightnessFadeEnabled %}
{% set rawLightLevel = state_attr(light, 'brightness') %}
{## If a light is off, its brightness will return "None"? So first check if there's a valid brightness before getting the value ##}
{% if rawLightLevel %}
{% set currentLightLevel = rawLightLevel | int %}
{% else %}
{% set currentLightLevel = 0 %}
{% endif %}
{% if lampBrightnessScale == "zeroToOneHundred" %}
{% set currentLightLevel = (currentLightLevel / 2.55) | round(0) %}
{% endif %}
{% else %}
{% set currentLightLevel = startBrightness %}
{% endif %}
{{ currentLightLevel }}
expectedColorTemperature: |
{% if isColorFadeEnabled %}
{% set startColorTemperature = startColorTemperature | int %}
{% set colorTemperatureSpan = colorTemperatureSpan | int %}
{% set easingAdjustedPercentageCompleted = easingAdjustedPercentageCompleted | float(0) %}
{% set calculatedColorTemperature = (startColorTemperature + (colorTemperatureSpan * easingAdjustedPercentageCompleted)) | round(0) %}
{% set minColorTemperatureKelvin = minColorTemperatureKelvin | int %}
{% set maxColorTemperatureKelvin = maxColorTemperatureKelvin | int %}
{% if (calculatedColorTemperature < minColorTemperatureKelvin) %}
{% set calculatedColorTemperature = minColorTemperatureKelvin %}
{% elif (calculatedColorTemperature > maxColorTemperatureKelvin) %}
{% set calculatedColorTemperature = maxColorTemperatureKelvin %}
{% endif %}
{% if (endColorTemperature >= startColorTemperature) and (calculatedColorTemperature > endColorTemperature) %}
{% set calculatedColorTemperature = endColorTemperature %}
{% elif (endColorTemperature < startColorTemperature) and (calculatedColorTemperature < endColorTemperature) %}
{% set calculatedColorTemperature = endColorTemperature %}
{% endif %}
{% else %}
{% set calculatedColorTemperature = 0 %}
{% endif %}
{{ calculatedColorTemperature }}
currentColorTemperature: |
{## init ##}
{% set currentColorTemperature = -1 %}
{% if isColorFadeEnabled %}
{% set rawColorTemperature = state_attr(light, 'color_temp_kelvin') %}
{## If a light is off or if its color temperature is defined using a non-Kelvin color system, its color temperature will return "None"? So first check if there's a valid color temperature ##}
{% if rawColorTemperature %}
{% if is_number(rawColorTemperature) %}
{% set currentColorTemperature = rawColorTemperature | int %}
{% endif %}
{% endif %}
{% endif %}
{{ currentColorTemperature }}
- if:
- condition: template
value_template: |
{{ isBrightnessFadeEnabled and isColorFadeEnabled }}
then:
- if:
- condition: template
value_template: |
{{
(
( (currentBrightness | int) != (endBrightness | int) )
and
( (currentBrightness | int) != (expectedBrightness | int) )
)
or
(
( (currentColorTemperature | int) != (endColorTemperature | int) )
and
( (currentColorTemperature | int) != (expectedColorTemperature | int) )
)
}}
then:
- if:
- condition: template
value_template: |
{{ shouldUseNativeLampTransitionsToo }}
then:
- if:
- condition: template
value_template: |
{{ (lampBrightnessScale == "zeroToTwoFiftyFive") }}
then:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness: "{{ expectedBrightness }}"
kelvin: "{{ expectedColorTemperature }}"
transition: "{{ transitionTimeParameterInSeconds | float(0) }}"
else:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness_pct: "{{ expectedBrightness }}"
kelvin: "{{ expectedColorTemperature }}"
transition: "{{ transitionTimeParameterInSeconds | float(0) }}"
else:
- if:
- condition: template
value_template: |
{{ (lampBrightnessScale == "zeroToTwoFiftyFive") }}
then:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness: "{{ expectedBrightness }}"
kelvin: "{{ expectedColorTemperature }}"
else:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness_pct: "{{ expectedBrightness }}"
kelvin: "{{ expectedColorTemperature }}"
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- if:
- condition: template
value_template: |
{{ isColorFadeEnabled and isBrightnessFadeEnabled }}
then:
- service: system_log.write
data_template:
message: >
Set {{ lightFriendlyName }} to {{
expectedBrightness | int }} brightness and {{
expectedColorTemperature | int }}°K. (Linear
brightness would have been {{
linearExpectedBrightness | int }}.) Delay is {{
delayInMilliseconds | int }} ms. Elapsed time is
{{ (as_timestamp(now()) - startTimestamp) |
round(2) }} seconds. (endBrightness is {{
endBrightness}} and endColorTemperature is {{
endColorTemperature}}.)
level: warning
else:
- if:
- condition: template
value_template: |
{{ isBrightnessFadeEnabled and
(
( (currentBrightness | int) != (endBrightness | int) )
and
( (currentBrightness | int) != (expectedBrightness | int) )
)
}}
then:
- if:
- condition: template
value_template: |
{{ shouldUseNativeLampTransitionsToo }}
then:
- if:
- condition: template
value_template: |
{{ (lampBrightnessScale == "zeroToTwoFiftyFive") }}
then:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness: "{{ expectedBrightness }}"
transition: "{{ transitionTimeParameterInSeconds }}"
else:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness_pct: "{{ expectedBrightness }}"
transition: "{{ transitionTimeParameterInSeconds }}"
else:
- if:
- condition: template
value_template: |
{{ (lampBrightnessScale == "zeroToTwoFiftyFive") }}
then:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness: "{{ expectedBrightness }}"
else:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness_pct: "{{ expectedBrightness }}"
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: >
Set {{ lightFriendlyName }} to {{ expectedBrightness |
int }} brightness. (Linear brightness would have been
{{ linearExpectedBrightness | int }}.) Delay is {{
delayInMilliseconds | int }} ms. Elapsed time is {{
(as_timestamp(now()) - startTimestamp) | round(2) }}
seconds. (endBrightness is {{ endBrightness}}.)
level: warning
else:
- if:
- condition: template
value_template: |
{{ isColorFadeEnabled and
(
( (currentColorTemperature | int) != (endColorTemperature | int) )
and
( (currentColorTemperature | int) != (expectedColorTemperature | int) )
)
}}
then:
- if:
- condition: template
value_template: |
{{ shouldUseNativeLampTransitionsToo }}
then:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
kelvin: "{{ expectedColorTemperature }}"
transition: "{{ transitionTimeParameterInSeconds | round(3) }}"
else:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
kelvin: "{{ expectedColorTemperature }}"
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: >
Set {{ lightFriendlyName }} to {{
expectedColorTemperature | int }}°K. Delay is {{
delayInMilliseconds | int }} ms. Elapsed time is
{{ (as_timestamp(now()) - startTimestamp) |
round(2) }} seconds. (endColorTemperature is {{
endColorTemperature}}.)
level: warning
- delay:
milliseconds: "{{ delayInMilliseconds | float(0) }}"
- if:
- condition: template
value_template: >
{## init ##} {% set shouldStop = false %} {% if
isStopEntityEnabled %}
{% if (shouldInvertTheValueOfTheStopEntity is defined) and shouldInvertTheValueOfTheStopEntity %}
{% if not bool(states(stopEntity), false) %}
{% set shouldStop = true %}
{% endif %}
{% else %}
{% if bool(states(stopEntity), false) %}
{% set shouldStop = true %}
{% endif %}
{% endif %}
{% endif %} {{ shouldStop }}
then:
- if:
- condition: template
value_template: >
{{ (shouldInvertTheValueOfTheStopEntity is defined) and
shouldInvertTheValueOfTheStopEntity }}
then:
- variables:
stopMessage: >
{% set stopMessage = "Stopped Ashley’s Light Fader because
" + (stopEntityFriendlyName | string) + " turned off." %}
{{ stopMessage }}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: |
{{ stopMessage }}
level: warning
- stop: |
{{ stopMessage }}
else:
- variables:
stopMessage: >
{% set stopMessage = "Stopped Ashley’s Light Fader because
" + (stopEntityFriendlyName | string) + " turned on." %}
{{ stopMessage }}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: |
{{ stopMessage }}
level: warning
- stop: |
{{ stopMessage }}
- variables:
currentBrightness: |+
{% if is_state(light, 'off') %}
{% set currentLightLevel = 0 %}
{{ currentLightLevel }}
{% else %}
{% set rawLightLevel = state_attr(light, 'brightness') %}
{## If a light is off, its brightness will return 'None'. So first check if there's a valid brightness before getting the value ##}
{% if rawLightLevel %}
{% set currentLightLevel = rawLightLevel | int %}
{% else %}
{% set currentLightLevel = 0 %}
{% endif %}
{% if lampBrightnessScale == "zeroToOneHundred" %}
{% set currentLightLevel = (currentLightLevel / 2.55) | round(0) %}
{% endif %}
{{ currentLightLevel }}
{% endif %}
brightnessDifferenceFromExpected: >
{{ ( (currentBrightness | int) - (expectedBrightness | int) ) |
abs }}
isBrightnessDifferenceAboveAutoCancelThreshold: >
{% if shouldAutoCancelTheFadeIfTheLampBrightnessIsManuallyChanged
%}
{{ (brightnessDifferenceFromExpected | int) >= (normalizedAutoCancelThreshold | int) }}
{% else %}
{{ false }}
{% endif %}
- if:
- condition: template
value_template: |
{{ (
(
(not (shouldStopIfTheLampIsTurnedOffDuringTheFade is defined)) or
(
(shouldStopIfTheLampIsTurnedOffDuringTheFade is defined) and
shouldStopIfTheLampIsTurnedOffDuringTheFade
)
)
and ( ((expectedBrightness | int) > 0) and ((currentBrightness | int) == 0) )
)
}}
then:
- variables:
stopMessage: >
{% set stopMessage = "Stopped Ashley’s Light Fader because " +
(lightFriendlyName | string) + " was turned off during the
fade." %}
{{ stopMessage }}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: |
{{ stopMessage }}
level: warning
- stop: |
{{ stopMessage }}
- if:
- condition: template
value_template: >
{{ shouldAutoCancelTheFadeIfTheLampBrightnessIsManuallyChanged
and isBrightnessDifferenceAboveAutoCancelThreshold }}
then:
- variables:
stopMessage: >
{% if lampBrightnessScale == "zeroToTwoFiftyFive" %}
{% set currentBrightnessAsPercentage = (currentBrightness / 2.55) | round(0) %}
{% set expectedBrightnessAsPercentage = (expectedBrightness / 2.55) | round(0) %}
{% set differenceFromExpectedAsPercentage = (brightnessDifferenceFromExpected / 2.55) | round(0) %}
{% else %}
{% set currentBrightnessAsPercentage = currentBrightness %}
{% set expectedBrightnessAsPercentage = expectedBrightness %}
{% set differenceFromExpectedAsPercentage = brightnessDifferenceFromExpected %}
{% endif %}
{% set stopMessage = "Stopped Ashley’s Light Fader because " +
(lightFriendlyName | string) + " was found to be at " +
(currentBrightnessAsPercentage | string) + "%, a difference of
" + (differenceFromExpectedAsPercentage | string) + "
percentage points from the expected brightness of " +
(expectedBrightnessAsPercentage | string) + "%, which is
higher than the auto-cancel threshold of " +
(autoCancelThreshold | string) + " percentage points." %}
{{ stopMessage }}
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- service: system_log.write
data_template:
message: |
{{ stopMessage }}
level: warning
- stop: |
{{ stopMessage }}
until:
- condition: template
value_template: |+
{% if (as_timestamp(now()) >= endTimestamp) %}
{{ true }}
{% elif isBrightnessFadeEnabled or isColorFadeEnabled %}
{## init ##}
{% set okayToEndTheLoop = true %}
{% if isBrightnessFadeEnabled %}
{% set rawLightLevel = state_attr(light, 'brightness') %}
{## If a light is off, its brightness will return "None"? So first check if there's a valid brightness before getting the value ##}
{% if rawLightLevel %}
{% set currentLightLevel = rawLightLevel | int %}
{% else %}
{% set currentLightLevel = 0 %}
{% endif %}
{% if lampBrightnessScale == "zeroToOneHundred" %}
{% set currentLightLevel = (currentLightLevel / 2.55) | round(0) %}
{% endif %}
{% if (endBrightness >= startBrightness) and (currentLightLevel < endBrightness) %}
{% set okayToEndTheLoop = false %}
{% elif (endBrightness < startBrightness) and (currentLightLevel > endBrightness) %}
{% set okayToEndTheLoop = false %}
{% endif %}
{% endif %}
{## The "and okayToEndTheLoop" part is to avoid needlessly checking whether the color temp fails if the brightness check already fails ##}
{% if isColorFadeEnabled and okayToEndTheLoop %}
{## init ##}
{% set currentColorTemperature = -1 %}
{% set rawColorTemperature = state_attr(light, 'color_temp_kelvin') %}
{## If a light is off or if its color temperature is defined using a non-Kelvin color system, its color temperature will return "None"? So first check if there's a valid color temperature ##}
{% if rawColorTemperature %}
{% if is_number(rawColorTemperature) %}
{% set currentColorTemperature = rawColorTemperature | int %}
{% endif %}
{% endif %}
{% if (currentColorTemperature != -1) and (endColorTemperature >= startColorTemperature) and (currentColorTemperature < endColorTemperature) %}
{% set okayToEndTheLoop = false %}
{% elif (currentColorTemperature != -1) and (endColorTemperature < startColorTemperature) and (currentColorTemperature > endColorTemperature) %}
{% set okayToEndTheLoop = false %}
{% endif %}
{% endif %}
{{ okayToEndTheLoop }}
{% else %}
{## neither isBrightnessFadeEnabled nor isColorFadeEnabled ##}
{{ true }}
{% endif %}
- variables:
currentBrightness: |+
{% set rawLightLevel = state_attr(light, 'brightness') %}
{## If a light is off, its brightness will return 'None'. So first check if there's a valid brightness before getting the value ##}
{% if rawLightLevel %}
{% set currentLightLevel = rawLightLevel | int %}
{% else %}
{% set currentLightLevel = 0 %}
{% endif %}
{% if lampBrightnessScale == "zeroToOneHundred" %}
{% set currentLightLevel = (currentLightLevel / 2.55) | round(0) %}
{% endif %}
{{ currentLightLevel }}
brightnessDifferenceFromExpected: |
{{ ( (currentBrightness | int) - (endBrightness | int) ) | abs }}
isBrightnessDifferenceAboveAutoCancelThreshold: |
{% if shouldAutoCancelTheFadeIfTheLampBrightnessIsManuallyChanged %}
{{ (brightnessDifferenceFromExpected | int) > (normalizedAutoCancelThreshold | int) }}
{% else %}
{{ false }}
{% endif %}
currentColorTemperature: >
{## init ##} {% set currentColorTemperature = -1 %} {% if
isColorFadeEnabled %}
{% set rawColorTemperature = state_attr(light, 'color_temp_kelvin') %}
{## If a light is off or if its color temperature is defined using a non-Kelvin color system, its color temperature will return "None"? So first check if there's a valid color temperature ##}
{% if rawColorTemperature %}
{% if is_number(rawColorTemperature) %}
{% set currentColorTemperature = rawColorTemperature | int %}
{% endif %}
{% endif %}
{% endif %}
{{ currentColorTemperature }}
- if:
- condition: template
value_template: |
{{ (
(not shouldAutoCancelTheFadeIfTheLampBrightnessIsManuallyChanged) or
(not isBrightnessDifferenceAboveAutoCancelThreshold)
)
and
(
(not (shouldStopIfTheLampIsTurnedOffDuringTheFade is defined)) or
(not shouldStopIfTheLampIsTurnedOffDuringTheFade) or
((currentBrightness | int) != 0)
)
}}
then:
- if:
- condition: template
value_template: |
{{ isColorFadeEnabled and isBrightnessFadeEnabled
and
(
(isBrightnessFadeEnabled and ((currentBrightness | int) != (endBrightness | int)) )
or (isColorFadeEnabled and ((currentColorTemperature | int) != (endColorTemperature | int)) )
)
}}
then:
- if:
- condition: template
value_template: |
{{ (lampBrightnessScale == "zeroToTwoFiftyFive") }}
then:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness: "{{ endBrightness }}"
kelvin: "{{ endColorTemperature }}"
else:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness_pct: "{{ endBrightness }}"
kelvin: "{{ endColorTemperature }}"
else:
- if:
- condition: template
value_template: >
{{ isBrightnessFadeEnabled and ((currentBrightness | int) !=
(endBrightness | int)) }}
then:
- if:
- condition: template
value_template: |
{{ (lampBrightnessScale == "zeroToTwoFiftyFive") }}
then:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness: "{{ endBrightness }}"
else:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness_pct: "{{ endBrightness }}"
else:
- if:
- condition: template
value_template: >
{{ isColorFadeEnabled and ((currentColorTemperature | int)
!= (endColorTemperature | int)) }}
then:
- service: light.turn_on
target:
entity_id: "{{ light }}"
data:
kelvin: "{{ endColorTemperature }}"
- if:
- condition: template
value_template: |
{{ isDebugMode }}
then:
- if:
- condition: template
value_template: |
{{ isColorFadeEnabled and isBrightnessFadeEnabled }}
then:
- service: system_log.write
data_template:
message: >
Set {{ lightFriendlyName }} to {{ endBrightness | int }}
brightness and {{ endColorTemperature | int }}°K. Elapsed
time is {{ (as_timestamp(now()) - startTimestamp) | round(2)
}} seconds.
level: warning
else:
- if:
- condition: template
value_template: |
{{ isBrightnessFadeEnabled }}
then:
- service: system_log.write
data_template:
message: >
Set {{ lightFriendlyName }} to {{ endBrightness | int }}
brightness. Elapsed time is {{ (as_timestamp(now()) -
startTimestamp) | round(2) }} seconds.
level: warning
else:
- if:
- condition: template
value_template: |
{{ isColorFadeEnabled }}
then:
- service: system_log.write
data_template:
message: >
Set {{ lightFriendlyName }} to {{
endColorTemperature | int }}°K. Elapsed time is {{
(as_timestamp(now()) - startTimestamp) | round(2) }}
seconds.
level: warning
mode: parallel
max: 15
icon: mdi:lightbulb-on-50
@alirezadigi
Copy link

Hi, and thank you for your great idea. It has finally solved my fading problem!

I have made some edits to your script configuration and added Kelvin temperature input to create a sunrise-like effect. It feels better now!

I have uploaded the edited code to this GitHub gist: https://gist.github.com/alirezadigi/fc9044948cdc6525bc120a5ae186a92c

I would appreciate it if you could take a look and provide any feedback or suggestions. Thank you once again for your help!
Best regards,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment