adaptive-lighting/custom_components/adaptive_lighting/__init__.py

111 lines
3.6 KiB
Python
Raw Normal View History

2020-09-28 13:10:41 +02:00
"""Adaptive Lighting integration in Home-Assistant.
2020-09-26 13:12:06 +02:00
2020-09-28 13:10:41 +02:00
This integration calculates color temperature and brightness to synchronize
2020-09-26 13:12:06 +02:00
your color-changing lights with the perceived color temperature of the sky
throughout the day. This gives your environment a more natural feel, with
cooler whites during the midday and warmer tints near twilight and dawn.
2020-09-19 11:10:54 +02:00
2020-09-28 13:10:41 +02:00
Additionally, the integration sets your lights to a nice warm white at 1% in
2020-09-26 13:12:06 +02:00
"Sleep mode", which is far brighter than starlight but won't reset your
circadian rhythm or break down too much rhodopsin in your eyes.
2020-09-19 11:10:54 +02:00
Human circadian rhythms are heavily influenced by ambient light levels and
2020-09-26 13:12:06 +02:00
hues. Hormone production, brainwave activity, mood, and wakefulness are
2020-09-19 11:10:54 +02:00
just some of the cognitive functions tied to cyclical natural light.
2020-09-26 13:12:06 +02:00
Resources:
- http://en.wikipedia.org/wiki/Zeitgeber
- http://www.cambridgeincolour.com/tutorials/sunrise-sunset-calculator.htm
- http://en.wikipedia.org/wiki/Color_temperature
2020-09-19 11:10:54 +02:00
2020-09-26 13:12:06 +02:00
## Notes
* Only your location is taken into account to calculate the the sun's position.
2020-09-28 13:10:41 +02:00
* Weather is not considered.
* The integration does not calculate a true "Blue Hour" -- it just sets the
2020-09-26 13:12:06 +02:00
lights to 2700K (warm white) until your hub goes into "Sleep mode".
2020-09-19 11:10:54 +02:00
"""
2020-09-19 11:35:28 +02:00
import logging
2020-10-05 23:41:57 +02:00
from typing import Any, Dict
2020-09-23 13:11:50 +02:00
2020-09-23 18:20:25 +02:00
import voluptuous as vol
2020-09-24 20:41:24 +02:00
2020-09-20 18:38:01 +02:00
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
2020-10-05 23:41:57 +02:00
from homeassistant.const import CONF_SOURCE
from homeassistant.core import HomeAssistant
2020-09-26 17:39:17 +02:00
import homeassistant.helpers.config_validation as cv
2020-09-19 11:10:54 +02:00
2020-09-30 00:42:27 +02:00
from .const import (
_DOMAIN_SCHEMA,
ATTR_TURN_ON_OFF_LISTENER,
CONF_NAME,
DOMAIN,
UNDO_UPDATE_LISTENER,
)
2020-09-19 11:10:54 +02:00
2020-09-20 18:38:01 +02:00
_LOGGER = logging.getLogger(__name__)
PLATFORMS = ["switch"]
2020-09-19 11:10:54 +02:00
2020-09-23 13:11:50 +02:00
2020-09-26 13:13:44 +02:00
def _all_unique_names(value):
2020-10-05 23:41:57 +02:00
"""Validate that all entities have a unique profile name."""
2020-09-23 18:20:25 +02:00
hosts = [device[CONF_NAME] for device in value]
schema = vol.Schema(vol.Unique())
schema(hosts)
return value
2020-09-24 20:41:24 +02:00
CONFIG_SCHEMA = vol.Schema(
2020-09-26 13:13:44 +02:00
{DOMAIN: vol.All(cv.ensure_list, [_DOMAIN_SCHEMA], _all_unique_names)},
2020-09-24 20:41:24 +02:00
extra=vol.ALLOW_EXTRA,
)
2020-09-23 18:20:25 +02:00
2020-10-05 23:41:57 +02:00
async def async_setup(hass: HomeAssistant, config: Dict[str, Any]):
2020-09-19 11:10:54 +02:00
"""Import integration from config."""
if DOMAIN in config:
for entry in config[DOMAIN]:
hass.async_create_task(
hass.config_entries.flow.async_init(
2020-10-05 23:41:57 +02:00
DOMAIN, context={CONF_SOURCE: SOURCE_IMPORT}, data=entry
)
2020-09-19 11:10:54 +02:00
)
return True
2020-10-05 23:41:57 +02:00
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry):
2020-09-19 11:10:54 +02:00
"""Set up the component."""
2020-09-28 23:39:55 +02:00
data = hass.data.setdefault(DOMAIN, {})
2020-09-19 11:10:54 +02:00
undo_listener = config_entry.add_update_listener(async_update_options)
2020-09-28 23:39:55 +02:00
data[config_entry.entry_id] = {UNDO_UPDATE_LISTENER: undo_listener}
for platform in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, platform)
)
2020-09-19 11:10:54 +02:00
return True
async def async_update_options(hass, config_entry: ConfigEntry):
"""Update options."""
await hass.config_entries.async_reload(config_entry.entry_id)
async def async_unload_entry(hass, config_entry: ConfigEntry) -> bool:
"""Unload a config entry."""
2020-09-29 13:13:08 +02:00
unload_ok = await hass.config_entries.async_forward_entry_unload(
config_entry, "switch"
)
2020-09-28 23:39:55 +02:00
data = hass.data[DOMAIN]
data[config_entry.entry_id][UNDO_UPDATE_LISTENER]()
2020-09-30 00:42:27 +02:00
if len(data) == 1: # no more config_entries
2020-10-05 23:41:57 +02:00
turn_on_off_listener = data.pop(ATTR_TURN_ON_OFF_LISTENER)
turn_on_off_listener.remove_listener()
turn_on_off_listener.remove_listener2()
2020-09-20 18:38:01 +02:00
if unload_ok:
2020-09-28 23:39:55 +02:00
data.pop(config_entry.entry_id)
2020-09-20 18:38:01 +02:00
return unload_ok