Unfortunately. I cannot get my aging brain to understand and code HA Automations . All my coding for this problem is in Python using Appdeamon. Hopefully, there is something useful in the code you can adapt.
Just a rundown on my setup
6 Tradfri lights in two sets of 3 connected to a single xiaomi aqara (ZigBee) switch
3 bulbs are in light group light.living_room_lights
3 bulbs are in light group light.dining_room lights
I use the above combination as xiaomi aqara does not support dimming. I did try using a wireless switch and leaving the tradfri bulbs permanently on and tried to avoid the whole issue. As they are the main lights they have to work, so after a couple of failure in HA I abandoned the wireless switch.
To keep things simple I have 3 predetermined dim modes Dark, relaxed and Bright. All controlled via Alexa or HA via an input select.
light_state:
name: Living Room Light State
options:
- "Off"
- Dark
- Relaxed
- Bright
initial: "Off"
icon: mdi:lightbulb
The first thing I needed was a reliable sensor to tell the automations the state of lights. With that you know if you can issue instructions to the lights or if you need to wait. So I use a template sensor.
lrsync:
friendly_name: 'Livingroom Light Sync'
value_template: >-
{% if is_state('light.lr1_2', 'unavailable')
and is_state('light.lr2', 'unavailable')
and is_state('light.lr3_2', 'unavailable')
and is_state('light.dr1', 'unavailable')
and is_state('light.dr2', 'unavailable')
and is_state('light.dr3', 'unavailable') %}
off
{% elif not is_state('light.lr1_2', 'unavailable')
and not is_state('light.lr2', 'unavailable')
and not is_state('light.lr3_2', 'unavailable')
and not is_state('light.dr1', 'unavailable')
and not is_state('light.dr2', 'unavailable')
and not is_state('light.dr3', 'unavailable') %}
on
{% else %}
unknown
{% endif %}
As I have multiple lights in a two light groups, the sensor can only trigger in sync when all the lights are available. If any lights fail the test the sensor is in an Unknown state or if all fail it is off.
So when I issue a Dim command from Alexa or the Lovelace UI. I first check the sensor to see if I can issue the command. If the sensor is in sync no problem just issue the command to set the input select. If the lights are off I just abandon the actual call to the lights, but I set up the logic as if I turned on the lights ( set input select to dark, relaxed or bright ) and turn on the light switch and wait.
In Appdemon API not only can you trigger when an entity changes but you can determine it’s previous state. So when my Sync sensor triggers on. The first thing I do is test if its previous state was off or unknown, if so I know I must complete the command abandoned above.
So here are code fragments.
The physical light switch
# Program to sync Tradfri lights to Physical switch
import appdaemon.plugins.hass.hassapi as hass
class LRswitch(hass.Hass):
def initialize(self):
self.handle = None
self.listen_state(self.lrswitch,"switch.wall_switch_158d00016cf4bc")
def lrswitch(self, entity, attribute, old, new, kwargs):
if new == "on" :
# if switch turned on ensure light group is turn on .There is a bug if lights are turned off and on quickly group is still off so lights appear off
self.turn_on("light.all_living_room_lights")
self.cancel_timer(self.handle)
self.log("Living Room Light on ")
if new == "off" :
# if switch is off . Turn off light group and ensure timer is turned off in case light switched toggled quickly
self.handle=self.run_in(self.switchoff,10)
self.select_option("input_select.light_state","Off")
self.log("Living Room Light Off")
# routine to force Tradfri lights into unavaliable
def switchoff(self,kwargs):
if self.get_state("switch.wall_switch_158d00016cf4bc") == "off" :
self.log("force lights unavailable")
# ensure all lights are toggled to force unavailable
self.toggle("light.living_room_lights")
self.toggle("light.dining_room_lights")
Item select
#
# This program actions an Item select (Off Dark, Relaxed and bright ) on two set of Tradfri lights (living room and Dinning 3 in each set)
#These bulbs are located the same pysical room (open plan dining and living room)
# The program will change the brightness and colur temperture of both sets of lights or one set if the other set of bulbs is off.
#
#
import appdaemon.plugins.hass.hassapi as hass
class LRselector(hass.Hass):
def initialize(self):
# Triggered if the superset of bulbs has changed state on or off
self.listen_state(self.lrselect,"input_select.light_state")
def lrselect (self, entity, attribute, old, new, kwargs):
# Variable holds the default superset of bulbs (6 bulbs)
self.ent = "light.all_living_room_lights"
la = self.get_state(self.ent)
lr = self.get_state("light.living_room_lights")
dr = self.get_state("light.dining_room_lights")
# check to see if one subset of bulbs is on or off. If so changes the variable to the correct subset
if lr == "on" and dr != "on" :
self.ent = "light.living_room_lights"
if lr != "on" and dr == "on" :
self.ent = "light.dining_room_lights"
#check to sse which item of the item select has been selected
if new == "Off" :
# resets item select and ensures all switches used by Alexa to change bulb state is off
self.turn_off("switch.wall_switch_158d00016cf4bc")
self.turn_off("input_boolean.dark")
self.turn_off("input_boolean.relaxed")
self.turn_off("input_boolean.bright")
# if switch is off no power to tradfri bulbs. Once power applied unstable for 60 seconds so delay selection util bulbs ready
if new != "Off" and self.get_state("switch.wall_switch_158d00016cf4bc") == "off" :
self.turn_on("switch.wall_switch_158d00016cf4bc")
self.log("switch triggered")
if new == "Dark" :
# Selects dark settings and applys to all bulbs or subset. Set switch on for Alexa
if self.get_state("sensor.lrsync") == "on" :
self.dark()
else :
self.log("talk sync")
self.talk_sync()
self.turn_on("input_boolean.dark")
if new == "Relaxed" :
if self.get_state("sensor.lrsync") == "on" :
self.relaxed()
else :
self.log("talk sync")
self.talk_sync()
self.turn_on("input_boolean.relaxed")
# Selects relaxed settings and applys to all bulbs or subset. Set switch on for Alexa
if new == "Bright" :
if self.get_state("sensor.lrsync") == "on" :
self.bright()
else :
self.log("talk sync")
self.talk_sync()
self.turn_on("input_boolean.bright")
# Selects bright settings and applys to all bulbs or subset. Set switch on for Alexa
# routines to select bulbs warmth and brightness
def dark(self):
self.call_service("light/turn_on", entity_id = self.ent, brightness = 25, transition = 6 , color_temp = 450)
self.log("dark triggered")
def relaxed(self):
self.call_service("light/turn_on", entity_id = self.ent, brightness = 203, transition = 6 , color_temp = 367)
self.log("relaxed triggered")
def bright(self):
self.call_service("light/turn_on", entity_id = self.ent, brightness = 254, transition = 6 , color_temp = 250)
self.log("bright triggered")
def talk_sync(self):
self.call_service('media_player/alexa_tts', entity_id= "media_player.lr_dot",
message="Lights ar still syncronizing,please wait a moment before issuing further commands")
Sync lights if unavailable
# Program to sync Tradfri lights when power restored
import appdaemon.plugins.hass.hassapi as hass
class LRsync(hass.Hass):
def initialize(self):
self.handle = None
self.listen_state(self.lrsync,"sensor.lrsync",new="on")
def lrsync(self, entity, attribute, old, new, kwargs):
# ensure sync only triggered if previous state was unknown ie just turned on
if old == "unknown" :
self.log("sync triggered")
# if triggered by switch turned on, default lights to relaxed
# Also ensure Alexa is silent as not invoked by mood item select
if self.get_state("input_select.light_state") == "Off" :
self.select_option("input_select.light_state", "Relaxed")
# run delayed option from item select now lights are in sync
if self.get_state("input_select.light_state") == "Dark":
self.dark()
if self.get_state("input_select.light_state") == "Relaxed" :
self.relaxed()
if self.get_state("input_select.light_state") == "Bright":
self.bright()
# default setting for dark ,relaxed and bright
def dark(self):
self.call_service("light/turn_on", entity_id = "light.all_living_room_lights", brightness = 25, transition = 6 , color_temp = 450)
self.log("dark triggered")
def relaxed(self):
self.call_service("light/turn_on", entity_id = "light.all_living_room_lights", brightness = 203, transition = 6 , color_temp = 367)
self.log("relaxed triggered")
def bright(self):
self.call_service("light/turn_on", entity_id = "light.all_living_room_lights", brightness = 254, transition = 6 , color_temp = 250)
self.log("bright triggered")
This works for me as I have control of the power source , I know when the lights are off.
Hope this helps