1 """Flux for Home-Assistant.
3 The idea was taken from https://github.com/KpaBap/hue-flux/
6 from __future__
import annotations
10 from typing
import Any
12 import voluptuous
as vol
20 DOMAIN
as LIGHT_DOMAIN,
45 color_RGB_to_xy_brightness,
46 color_temperature_kelvin_to_mired,
47 color_temperature_to_rgb,
51 _LOGGER = logging.getLogger(__name__)
53 ATTR_UNIQUE_ID =
"unique_id"
55 CONF_START_TIME =
"start_time"
56 CONF_STOP_TIME =
"stop_time"
57 CONF_START_CT =
"start_colortemp"
58 CONF_SUNSET_CT =
"sunset_colortemp"
59 CONF_STOP_CT =
"stop_colortemp"
60 CONF_DISABLE_BRIGHTNESS_ADJUST =
"disable_brightness_adjust"
61 CONF_INTERVAL =
"interval"
66 DEFAULT_MODE = MODE_XY
68 PLATFORM_SCHEMA = vol.Schema(
70 vol.Required(CONF_PLATFORM):
"flux",
71 vol.Required(CONF_LIGHTS): cv.entity_ids,
72 vol.Optional(CONF_NAME, default=
"Flux"): cv.string,
73 vol.Optional(CONF_START_TIME): cv.time,
74 vol.Optional(CONF_STOP_TIME): cv.time,
75 vol.Optional(CONF_START_CT, default=4000): vol.All(
76 vol.Coerce(int), vol.Range(min=1000, max=40000)
78 vol.Optional(CONF_SUNSET_CT, default=3000): vol.All(
79 vol.Coerce(int), vol.Range(min=1000, max=40000)
81 vol.Optional(CONF_STOP_CT, default=1900): vol.All(
82 vol.Coerce(int), vol.Range(min=1000, max=40000)
84 vol.Optional(CONF_BRIGHTNESS): vol.All(
85 vol.Coerce(int), vol.Range(min=0, max=255)
87 vol.Optional(CONF_DISABLE_BRIGHTNESS_ADJUST): cv.boolean,
88 vol.Optional(CONF_MODE, default=DEFAULT_MODE): vol.Any(
89 MODE_XY, MODE_MIRED, MODE_RGB
91 vol.Optional(CONF_INTERVAL, default=30): cv.positive_int,
92 vol.Optional(ATTR_TRANSITION, default=30): VALID_TRANSITION,
93 vol.Optional(ATTR_UNIQUE_ID): cv.string,
99 """Set color of array of lights."""
101 if is_on(hass, light):
102 service_data = {ATTR_ENTITY_ID: light}
103 if x_val
is not None and y_val
is not None:
104 service_data[ATTR_XY_COLOR] = [x_val, y_val]
105 if brightness
is not None:
106 service_data[ATTR_BRIGHTNESS] = brightness
107 if transition
is not None:
108 service_data[ATTR_TRANSITION] = transition
109 await hass.services.async_call(LIGHT_DOMAIN, SERVICE_TURN_ON, service_data)
113 """Set color of array of lights."""
115 if is_on(hass, light):
116 service_data = {ATTR_ENTITY_ID: light}
117 if mired
is not None:
118 service_data[ATTR_COLOR_TEMP] =
int(mired)
119 if brightness
is not None:
120 service_data[ATTR_BRIGHTNESS] = brightness
121 if transition
is not None:
122 service_data[ATTR_TRANSITION] = transition
123 await hass.services.async_call(LIGHT_DOMAIN, SERVICE_TURN_ON, service_data)
127 """Set color of array of lights."""
129 if is_on(hass, light):
130 service_data = {ATTR_ENTITY_ID: light}
132 service_data[ATTR_RGB_COLOR] = rgb
133 if transition
is not None:
134 service_data[ATTR_TRANSITION] = transition
135 await hass.services.async_call(LIGHT_DOMAIN, SERVICE_TURN_ON, service_data)
141 async_add_entities: AddEntitiesCallback,
142 discovery_info: DiscoveryInfoType |
None =
None,
144 """Set up the Flux switches."""
145 name = config.get(CONF_NAME)
146 lights = config.get(CONF_LIGHTS)
147 start_time = config.get(CONF_START_TIME)
148 stop_time = config.get(CONF_STOP_TIME)
149 start_colortemp = config.get(CONF_START_CT)
150 sunset_colortemp = config.get(CONF_SUNSET_CT)
151 stop_colortemp = config.get(CONF_STOP_CT)
152 brightness = config.get(CONF_BRIGHTNESS)
153 disable_brightness_adjust = config.get(CONF_DISABLE_BRIGHTNESS_ADJUST)
154 mode = config.get(CONF_MODE)
155 interval = config.get(CONF_INTERVAL)
156 transition = config.get(ATTR_TRANSITION)
157 unique_id = config.get(ATTR_UNIQUE_ID)
168 disable_brightness_adjust,
176 async
def async_update(call: ServiceCall |
None =
None) ->
None:
178 await flux.async_flux_update()
180 service_name =
slugify(f
"{name} update")
181 hass.services.async_register(SWITCH_DOMAIN, service_name, async_update)
185 """Representation of a Flux switch."""
198 disable_brightness_adjust,
204 """Initialize the Flux switch."""
223 """Return the name of the device if any."""
224 return self.
_name_name
228 """Return true if switch is on."""
232 """Call when entity about to be added to hass."""
234 if last_state
and last_state.state == STATE_ON:
238 """Run when entity will be removed from hass."""
248 self.
unsub_trackerunsub_tracker = event.async_track_time_interval(
251 datetime.timedelta(seconds=self.
_interval_interval),
268 """Update all the lights using flux."""
278 if stop_time <= start_time:
282 stop_time += datetime.timedelta(days=1)
283 elif now < start_time:
285 stop_time -= datetime.timedelta(days=1)
287 if start_time < now < sunset:
291 day_length =
int(sunset.timestamp() - start_time.timestamp())
292 seconds_from_start =
int(now.timestamp() - start_time.timestamp())
293 percentage_complete = seconds_from_start / day_length
294 temp_offset = temp_range * percentage_complete
304 if stop_time < start_time
and stop_time.day == sunset.day:
306 sunset_time = sunset - datetime.timedelta(days=1)
310 night_length =
int(stop_time.timestamp() - sunset_time.timestamp())
311 seconds_from_sunset =
int(now.timestamp() - sunset_time.timestamp())
312 percentage_complete = seconds_from_sunset / night_length
314 percentage_complete = 1
317 temp_offset = temp_range * percentage_complete
327 if self.
_mode_mode == MODE_XY:
333 "Lights updated to x:%s y:%s brightness:%s, %s%% "
334 "of %s cycle complete at %s"
339 round(percentage_complete * 100),
343 elif self.
_mode_mode == MODE_RGB:
346 "Lights updated to rgb:%s, %s%% of %s cycle complete at %s",
348 round(percentage_complete * 100),
360 "Lights updated to mired:%s brightness:%s, %s%% "
361 "of %s cycle complete at %s"
365 round(percentage_complete * 100),
371 """Return sunrise or start_time if given."""
373 sunrise = now.replace(
381 """Return dusk or stop_time if given."""
None async_turn_on(self, **Any kwargs)
None async_will_remove_from_hass(self)
def async_flux_update(self, utcnow=None)
None async_turn_off(self, **Any kwargs)
None async_added_to_hass(self)
def find_stop_time(self, now)
_disable_brightness_adjust
def find_start_time(self, now)
def __init__(self, name, hass, lights, start_time, stop_time, start_colortemp, sunset_colortemp, stop_colortemp, brightness, disable_brightness_adjust, mode, interval, transition, unique_id)
None async_write_ha_state(self)
State|None async_get_last_state(self)
def async_set_lights_xy(hass, lights, x_val, y_val, brightness, transition)
def async_set_lights_rgb(hass, lights, rgb, transition)
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
def async_set_lights_temp(hass, lights, mired, brightness, transition)
datetime.datetime|None get_astral_event_date(HomeAssistant hass, str event, datetime.date|datetime.datetime|None date=None)
tuple[float, float, int] color_RGB_to_xy_brightness(int iR, int iG, int iB, GamutType|None Gamut=None)
tuple[float, float, float] color_temperature_to_rgb(float color_temperature_kelvin)
int color_temperature_kelvin_to_mired(float kelvin_temperature)
dt.datetime as_local(dt.datetime dattim)