forked from chazzu/hass-animated-scenes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path__init__.py
161 lines (126 loc) · 5.34 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""The Animated Scenes integration."""
import asyncio
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.light import (
DOMAIN as LIGHT_DOMAIN, ATTR_RGB_COLOR, ATTR_XY_COLOR, ATTR_COLOR_TEMP, ATTR_HS_COLOR,
ATTR_KELVIN)
from homeassistant.components.switch import (
DOMAIN as SWITCH_DOMAIN
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import SERVICE_TURN_ON, SERVICE_TURN_OFF
from homeassistant.core import HomeAssistant, State
from homeassistant.helpers.event import async_track_state_change_event
from .const import DOMAIN, CONF_EXTERNAL_SWITCHES
CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({
vol.Optional(CONF_EXTERNAL_SWITCHES): cv.entity_ids,
})}, extra=vol.ALLOW_EXTRA)
PLATFORMS = ["switch"]
async def async_setup(hass: HomeAssistant, config: dict):
switches = config.get(DOMAIN).get(CONF_EXTERNAL_SWITCHES)
if switches:
GLOBAL_SCENES.add_switches(switches)
await GLOBAL_SCENES.set_hass(hass)
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
for component in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, component)
)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
unload_ok = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(entry, component)
for component in PLATFORMS
]
)
)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
class AnimatedScenes:
def __init__(self):
self.hass: HomeAssistant = None
self.switches = []
self.scenes = {}
self.active_scene = None
self.stored_state = {}
async def activate_scene(self, scene):
if not self.hass:
return
active_scene = None
if self.active_scene and self.active_scene in self.scenes:
active_scene = self.scenes[self.active_scene]
if active_scene and active_scene.restore:
restore_lights = (list(list(set(active_scene.lights) - set(scene.lights))
+ list(set(scene.lights) - set(active_scene.lights))))
await self.restore_state(restore_lights)
await self.turn_off_all(scene.entity_id)
self.store_state(scene.lights)
self.active_scene = scene.entity_id
await scene.initialize()
def add_scene(self, scene):
self.scenes[scene.entity_id] = scene
def add_switches(self, switches):
self.switches.extend(switches)
async def deactivate_scene(self, scene):
if not self.hass:
return
if scene.restore and self.active_scene == scene.entity_id:
await self.restore_state(scene.lights)
if self.active_scene == scene.entity_id:
self.active_scene = None
async def set_hass(self, hass: HomeAssistant):
self.hass = hass
async_track_state_change_event(hass, self.switches, self.external_switch_changed)
def store_state(self, lights):
if not self.hass:
return
for light in lights:
if light not in self.stored_state and self.hass.states.get(light).state != 'off':
self.stored_state[light]: State = self.hass.states.get(light)
async def restore_state(self, lights):
if not self.hass:
return
for light in lights:
if light in self.stored_state:
state: State = self.stored_state[light]
if state.state == 'on':
await self.hass.services.async_call(LIGHT_DOMAIN, SERVICE_TURN_ON,
self._build_attributes_from_state(state))
else:
await self.hass.services.async_call(LIGHT_DOMAIN, SERVICE_TURN_OFF, {'entity_id': light})
del self.stored_state[light]
async def turn_off_all(self, on_switch=None):
for switch in self.switches:
if on_switch != switch:
await self.hass.services.async_call(SWITCH_DOMAIN, SERVICE_TURN_OFF, {'entity_id': switch})
for switch in self.scenes:
if on_switch != switch:
await self.hass.services.async_call(SWITCH_DOMAIN, SERVICE_TURN_OFF, {'entity_id': switch})
async def external_switch_changed(self, event):
state = event.data.get('new_state')
entity_id = event.data.get('entity_id')
if state.state == 'on':
await self.turn_off_all(entity_id)
self.active_scene = entity_id
elif state.state == 'off' and self.active_scene == entity_id:
await self.turn_off_all()
self.active_scene = None
def _build_attributes_from_state(self, state):
attributes = {
'entity_id': state.entity_id,
'brightness': state.attributes.get('brightness'),
'transition': 1
}
exclusive_properties = [ATTR_RGB_COLOR, ATTR_XY_COLOR, ATTR_HS_COLOR, ATTR_COLOR_TEMP, ATTR_KELVIN]
for attr in exclusive_properties:
value = state.attributes.get(attr)
if value:
attributes[attr] = value
break
return attributes
GLOBAL_SCENES = AnimatedScenes()