def validate_device_has_at_least_one_identifier(value: ConfigType) -> \ ConfigType: """Validate that a device info entry has at least one identifying value.""" if not value.get(CONF_IDENTIFIERS) and not value.get(CONF_CONNECTIONS): raise vol.Invalid("Device must have at least one identifying value in " "'identifiers' and/or 'connections'") return value
async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, async_add_devices, discovery_info=None): """Set up the WUnderground sensor.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) pws_id = config.get(CONF_PWS_ID) rest = WUndergroundData( hass, config.get(CONF_API_KEY), pws_id, config.get(CONF_LANG), latitude, longitude) if pws_id is None: unique_id_base = "@{:06f},{:06f}".format(longitude, latitude) else: # Manually specified weather station, use that for unique_id unique_id_base = pws_id sensors = [] for variable in config[CONF_MONITORED_CONDITIONS]: sensors.append(WUndergroundSensor(hass, rest, variable, unique_id_base)) await rest.async_update() if not rest.data: raise PlatformNotReady async_add_devices(sensors, True)
async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, async_add_devices, discovery_info=None): """Set up the cast platform.""" import pychromecast # Import CEC IGNORE attributes pychromecast.IGNORE_CEC += config.get(CONF_IGNORE_CEC, []) hass.data.setdefault(ADDED_CAST_DEVICES_KEY, {}) hass.data.setdefault(KNOWN_CHROMECASTS_KEY, {}) # None -> use discovery; (host, port) -> manually specify chromecast. want_host = None if discovery_info: want_host = (discovery_info.get('host'), discovery_info.get('port')) elif CONF_HOST in config: want_host = (config.get(CONF_HOST), DEFAULT_PORT) enable_discovery = False if want_host is None: # We were explicitly told to enable pychromecast discovery. enable_discovery = True elif want_host[1] != DEFAULT_PORT: # We're trying to add a group, so we have to use pychromecast's # discovery to get the correct friendly name. enable_discovery = True if enable_discovery: @callback def async_cast_discovered(chromecast): """Callback for when a new chromecast is discovered.""" if want_host is not None and \ (chromecast.host, chromecast.port) != want_host: return # for groups, only add requested device cast_device = _async_create_cast_device(hass, chromecast) if cast_device is not None: async_add_devices([cast_device]) async_dispatcher_connect(hass, SIGNAL_CAST_DISCOVERED, async_cast_discovered) # Re-play the callback for all past chromecasts, store the objects in # a list to avoid concurrent modification resulting in exception. for chromecast in list(hass.data[KNOWN_CHROMECASTS_KEY].values()): async_cast_discovered(chromecast) hass.async_add_job(_setup_internal_discovery, hass) else: # Manually add a "normal" Chromecast, we can do that without discovery. try: chromecast = await hass.async_add_job( pychromecast.Chromecast, *want_host) except pychromecast.ChromecastConnectionError as err: _LOGGER.warning("Can't set up chromecast on %s: %s", want_host[0], err) raise PlatformNotReady key = (chromecast.host, chromecast.port, chromecast.uuid) cast_device = _async_create_cast_device(hass, chromecast) if cast_device is not None: hass.data[KNOWN_CHROMECASTS_KEY][key] = chromecast async_add_devices([cast_device])
def setup_platform(hass, config: ConfigType, add_devices: Callable[[list], None], discovery_info=None): """Set up the Sesame platform.""" import pysesame email = config.get(CONF_EMAIL) password = config.get(CONF_PASSWORD) add_devices([SesameDevice(sesame) for sesame in pysesame.get_sesames(email, password)])
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: """Start the MQTT protocol service.""" conf = config.get(DOMAIN) # type: Optional[ConfigType] # We need this because discovery can cause components to be set up and # otherwise it will not load the users config. # This needs a better solution. hass.data[DATA_MQTT_HASS_CONFIG] = config if conf is None: # If we have a config entry, setup is done by that config entry. # If there is no config entry, this should fail. return bool(hass.config_entries.async_entries(DOMAIN)) conf = dict(conf) if CONF_EMBEDDED in conf or CONF_BROKER not in conf: if (conf.get(CONF_PASSWORD) is None and config.get('http', {}).get('api_password') is not None): _LOGGER.error( "Starting from release 0.76, the embedded MQTT broker does not" " use api_password as default password anymore. Please set" " password configuration. See https://home-assistant.io/docs/" "mqtt/broker#embedded-broker for details") return False broker_config = await _async_setup_server(hass, config) if broker_config is None: _LOGGER.error("Unable to start embedded MQTT broker") return False conf.update({ CONF_BROKER: broker_config[0], CONF_PORT: broker_config[1], CONF_USERNAME: broker_config[2], CONF_PASSWORD: broker_config[3], CONF_CERTIFICATE: broker_config[4], CONF_PROTOCOL: broker_config[5], CONF_CLIENT_KEY: None, CONF_CLIENT_CERT: None, CONF_TLS_INSECURE: None, }) hass.data[DATA_MQTT_CONFIG] = conf # Only import if we haven't before. if not hass.config_entries.async_entries(DOMAIN): hass.async_create_task(hass.config_entries.flow.async_init( DOMAIN, context={'source': config_entries.SOURCE_IMPORT}, data={} )) return True
def from_config(config: ConfigType, config_validation: bool=True): """Turn a condition configuration into a method.""" factory = getattr( sys.modules[__name__], FROM_CONFIG_FORMAT.format(config.get(CONF_CONDITION)), None) if factory is None: raise HomeAssistantError('Invalid condition "{}" specified {}'.format( config.get(CONF_CONDITION), config)) return factory(config, config_validation)
def zone_from_config(config: ConfigType, config_validation: bool = True) -> Callable[..., bool]: """Wrap action method with zone based condition.""" if config_validation: config = cv.ZONE_CONDITION_SCHEMA(config) entity_id = config.get(CONF_ENTITY_ID) zone_entity_id = config.get(CONF_ZONE) def if_in_zone(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool: """Test if condition.""" return zone(hass, zone_entity_id, entity_id) return if_in_zone
def state_from_config(config: ConfigType, config_validation: bool = True) -> Callable[..., bool]: """Wrap action method with state based condition.""" if config_validation: config = cv.STATE_CONDITION_SCHEMA(config) entity_id = config.get(CONF_ENTITY_ID) req_state = cast(str, config.get(CONF_STATE)) for_period = config.get('for') def if_state(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool: """Test if condition.""" return state(hass, entity_id, req_state, for_period) return if_state
def async_from_config(config: ConfigType, config_validation: bool = True): """Turn a condition configuration into a method. Should be run on the event loop. """ for fmt in (ASYNC_FROM_CONFIG_FORMAT, FROM_CONFIG_FORMAT): factory = getattr(sys.modules[__name__], fmt.format(config.get(CONF_CONDITION)), None) if factory: break if factory is None: raise HomeAssistantError('Invalid condition "{}" specified {}'.format(config.get(CONF_CONDITION), config)) return factory(config, config_validation)
def time_from_config(config: ConfigType, config_validation: bool = True) -> Callable[..., bool]: """Wrap action method with time based condition.""" if config_validation: config = cv.TIME_CONDITION_SCHEMA(config) before = config.get(CONF_BEFORE) after = config.get(CONF_AFTER) weekday = config.get(CONF_WEEKDAY) def time_if(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool: """Validate time based if-condition.""" return time(before, after, weekday) return time_if
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the recorder.""" conf = config.get(DOMAIN, {}) keep_days = conf.get(CONF_PURGE_KEEP_DAYS) purge_interval = conf.get(CONF_PURGE_INTERVAL) if keep_days is None and purge_interval != 0: _LOGGER.warning( "From version 0.64.0 the 'recorder' component will by default " "purge data older than 10 days. To keep data longer you must " "configure 'purge_keep_days' or 'purge_interval'.") db_url = conf.get(CONF_DB_URL, None) if not db_url: db_url = DEFAULT_URL.format( hass_config_path=hass.config.path(DEFAULT_DB_FILE)) include = conf.get(CONF_INCLUDE, {}) exclude = conf.get(CONF_EXCLUDE, {}) instance = hass.data[DATA_INSTANCE] = Recorder( hass=hass, keep_days=keep_days, purge_interval=purge_interval, uri=db_url, include=include, exclude=exclude) instance.async_initialize() instance.start() @asyncio.coroutine def async_handle_purge_service(service): """Handle calls to the purge service.""" instance.do_adhoc_purge(service.data[ATTR_KEEP_DAYS]) hass.services.async_register( DOMAIN, SERVICE_PURGE, async_handle_purge_service, schema=SERVICE_PURGE_SCHEMA) return (yield from instance.async_db_ready)
def async_setup_scanner_platform(hass: HomeAssistantType, config: ConfigType, scanner: Any, async_see_device: Callable): """Helper method to connect scanner-based platform to device tracker. This method is a coroutine. """ interval = config.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL) # Initial scan of each mac we also tell about host name for config seen = set() # type: Any def device_tracker_scan(now: dt_util.dt.datetime): """Called when interval matches.""" found_devices = scanner.scan_devices() for mac in found_devices: if mac in seen: host_name = None else: host_name = scanner.get_device_name(mac) seen.add(mac) hass.add_job(async_see_device(mac=mac, host_name=host_name)) async_track_utc_time_change( hass, device_tracker_scan, second=range(0, 60, interval)) hass.async_add_job(device_tracker_scan, None)
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the recorder.""" conf = config.get(DOMAIN, {}) keep_days = conf.get(CONF_PURGE_KEEP_DAYS) purge_interval = conf.get(CONF_PURGE_INTERVAL) db_url = conf.get(CONF_DB_URL, None) if not db_url: db_url = DEFAULT_URL.format( hass_config_path=hass.config.path(DEFAULT_DB_FILE)) include = conf.get(CONF_INCLUDE, {}) exclude = conf.get(CONF_EXCLUDE, {}) instance = hass.data[DATA_INSTANCE] = Recorder( hass=hass, keep_days=keep_days, purge_interval=purge_interval, uri=db_url, include=include, exclude=exclude) instance.async_initialize() instance.start() @asyncio.coroutine def async_handle_purge_service(service): """Handle calls to the purge service.""" instance.do_adhoc_purge(service.data[ATTR_KEEP_DAYS]) hass.services.async_register( DOMAIN, SERVICE_PURGE, async_handle_purge_service, schema=SERVICE_PURGE_SCHEMA) return (yield from instance.async_db_ready)
def sun_from_config(config: ConfigType, config_validation: bool = True) -> Callable[..., bool]: """Wrap action method with sun based condition.""" if config_validation: config = cv.SUN_CONDITION_SCHEMA(config) before = config.get('before') after = config.get('after') before_offset = config.get('before_offset') after_offset = config.get('after_offset') def time_if(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool: """Validate time based if-condition.""" return sun(hass, before, after, before_offset, after_offset) return time_if
def async_setup_scanner_platform(hass: HomeAssistantType, config: ConfigType, scanner: Any, async_see_device: Callable, platform: str): """Set up the connect scanner-based platform to device tracker. This method must be run in the event loop. """ interval = config.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL) update_lock = asyncio.Lock(loop=hass.loop) scanner.hass = hass # Initial scan of each mac we also tell about host name for config seen = set() # type: Any @asyncio.coroutine def async_device_tracker_scan(now: dt_util.dt.datetime): """Handle interval matches.""" if update_lock.locked(): _LOGGER.warning( "Updating device list from %s took longer than the scheduled " "scan interval %s", platform, interval) return with (yield from update_lock): found_devices = yield from scanner.async_scan_devices() for mac in found_devices: if mac in seen: host_name = None else: host_name = yield from scanner.async_get_device_name(mac) seen.add(mac) try: extra_attributes = (yield from scanner.async_get_extra_attributes(mac)) except NotImplementedError: extra_attributes = dict() kwargs = { 'mac': mac, 'host_name': host_name, 'source_type': SOURCE_TYPE_ROUTER, 'attributes': { 'scanner': scanner.__class__.__name__, **extra_attributes } } zone_home = hass.states.get(zone.ENTITY_ID_HOME) if zone_home: kwargs['gps'] = [zone_home.attributes[ATTR_LATITUDE], zone_home.attributes[ATTR_LONGITUDE]] kwargs['gps_accuracy'] = 0 hass.async_add_job(async_see_device(**kwargs)) async_track_time_interval(hass, async_device_tracker_scan, interval) hass.async_add_job(async_device_tracker_scan(None))
async def async_setup(hass: HomeAssistantType, config: ConfigType): """Set up UPnP component.""" conf_default = CONFIG_SCHEMA({DOMAIN: {}})[DOMAIN] conf = config.get(DOMAIN, conf_default) local_ip = await hass.async_add_executor_job(get_local_ip) hass.data[DOMAIN] = { 'config': conf, 'devices': {}, 'local_ip': config.get(CONF_LOCAL_IP, local_ip), 'ports': conf.get('ports', {}), } if conf is not None: hass.async_create_task(hass.config_entries.flow.async_init( DOMAIN, context={'source': config_entries.SOURCE_IMPORT})) return True
def setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the ISY 994 platform.""" hass.data[ISY994_NODES] = {} for domain in SUPPORTED_DOMAINS: hass.data[ISY994_NODES][domain] = [] hass.data[ISY994_WEATHER] = [] hass.data[ISY994_PROGRAMS] = {} for domain in SUPPORTED_DOMAINS: hass.data[ISY994_PROGRAMS][domain] = [] isy_config = config.get(DOMAIN) user = isy_config.get(CONF_USERNAME) password = isy_config.get(CONF_PASSWORD) tls_version = isy_config.get(CONF_TLS_VER) host = urlparse(isy_config.get(CONF_HOST)) ignore_identifier = isy_config.get(CONF_IGNORE_STRING) sensor_identifier = isy_config.get(CONF_SENSOR_STRING) enable_climate = isy_config.get(CONF_ENABLE_CLIMATE) if host.scheme == 'http': https = False port = host.port or 80 elif host.scheme == 'https': https = True port = host.port or 443 else: _LOGGER.error("isy994 host value in configuration is invalid") return False import PyISY # Connect to ISY controller. isy = PyISY.ISY(host.hostname, port, username=user, password=password, use_https=https, tls_ver=tls_version, log=_LOGGER) if not isy.connected: return False _categorize_nodes(hass, isy.nodes, ignore_identifier, sensor_identifier) _categorize_programs(hass, isy.programs) if enable_climate and isy.configuration.get('Weather Information'): _categorize_weather(hass, isy.climate) def stop(event: object) -> None: """Stop ISY auto updates.""" isy.auto_update = False # Listen for HA stop to disconnect. hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop) # Load platforms for the devices in the ISY controller that we support. for component in SUPPORTED_DOMAINS: discovery.load_platform(hass, component, DOMAIN, {}, config) isy.auto_update = True return True
def setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the ISY 994 platform.""" isy_config = config.get(DOMAIN) user = isy_config.get(CONF_USERNAME) password = isy_config.get(CONF_PASSWORD) tls_version = isy_config.get(CONF_TLS_VER) host = urlparse(isy_config.get(CONF_HOST)) port = host.port addr = host.geturl() hidden_identifier = isy_config.get( CONF_HIDDEN_STRING, DEFAULT_HIDDEN_STRING) sensor_identifier = isy_config.get( CONF_SENSOR_STRING, DEFAULT_SENSOR_STRING) global HIDDEN_STRING HIDDEN_STRING = hidden_identifier if host.scheme == 'http': addr = addr.replace('http://', '') https = False elif host.scheme == 'https': addr = addr.replace('https://', '') https = True else: _LOGGER.error("isy994 host value in configuration is invalid") return False addr = addr.replace(':{}'.format(port), '') import PyISY global PYISY PYISY = PyISY # Connect to ISY controller. global ISY ISY = PyISY.ISY(addr, port, username=user, password=password, use_https=https, tls_ver=tls_version, log=_LOGGER) if not ISY.connected: return False _categorize_nodes(hidden_identifier, sensor_identifier) _categorize_programs() if ISY.configuration.get('Weather Information'): _categorize_weather() # Listen for HA stop to disconnect. hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop) # Load platforms for the devices in the ISY controller that we support. for component in SUPPORTED_DOMAINS: discovery.load_platform(hass, component, DOMAIN, {}, config) ISY.auto_update = True return True
def async_setup_platform(hass: HomeAssistantType, config: ConfigType, async_add_devices, discovery_info=None): """Set up the WUnderground sensor.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) rest = WUndergroundData( hass, config.get(CONF_API_KEY), config.get(CONF_PWS_ID), config.get(CONF_LANG), latitude, longitude) sensors = [] for variable in config[CONF_MONITORED_CONDITIONS]: sensors.append(WUndergroundSensor(hass, rest, variable)) yield from rest.async_update() if not rest.data: raise PlatformNotReady async_add_devices(sensors, True)
def setup(hass: HomeAssistant, config: ConfigType) -> bool: """Setup the recorder.""" global _INSTANCE # pylint: disable=global-statement if _INSTANCE is not None: _LOGGER.error('Only a single instance allowed.') return False purge_days = config.get(DOMAIN, {}).get(CONF_PURGE_DAYS) db_url = config.get(DOMAIN, {}).get(CONF_DB_URL, None) if not db_url: db_url = DEFAULT_URL.format( hass_config_path=hass.config.path(DEFAULT_DB_FILE)) _INSTANCE = Recorder(hass, purge_days=purge_days, uri=db_url) return True
def async_numeric_state_from_config(config: ConfigType, config_validation: bool = True) \ -> Callable[..., bool]: """Wrap action method with state based condition.""" if config_validation: config = cv.NUMERIC_STATE_CONDITION_SCHEMA(config) entity_id = config.get(CONF_ENTITY_ID) below = config.get(CONF_BELOW) above = config.get(CONF_ABOVE) value_template = config.get(CONF_VALUE_TEMPLATE) def if_numeric_state(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool: """Test numeric state condition.""" if value_template is not None: value_template.hass = hass return async_numeric_state( hass, entity_id, below, above, value_template, variables) return if_numeric_state
def setup_platform(hass: HomeAssistantType, config: ConfigType, add_entities: Callable[[list], None], discovery_info: Optional[dict] = None) -> bool: """Set up the GTFS sensor.""" gtfs_dir = hass.config.path(DEFAULT_PATH) data = str(config.get(CONF_DATA)) origin = config.get(CONF_ORIGIN) destination = config.get(CONF_DESTINATION) name = config.get(CONF_NAME) offset = config.get(CONF_OFFSET) include_tomorrow = config.get(CONF_TOMORROW) if not os.path.exists(gtfs_dir): os.makedirs(gtfs_dir) if not os.path.exists(os.path.join(gtfs_dir, data)): _LOGGER.error("The given GTFS data file/folder was not found") return False import pygtfs (gtfs_root, _) = os.path.splitext(data) sqlite_file = "{}.sqlite?check_same_thread=False".format(gtfs_root) joined_path = os.path.join(gtfs_dir, sqlite_file) gtfs = pygtfs.Schedule(joined_path) # pylint: disable=no-member if not gtfs.feeds: pygtfs.append_feed(gtfs, os.path.join(gtfs_dir, data)) add_entities([ GTFSDepartureSensor(gtfs, name, origin, destination, offset, include_tomorrow)]) return True
async def async_setup(hass: HomeAssistantType, config: ConfigType): """Set up the person component.""" component = EntityComponent(_LOGGER, DOMAIN, hass) conf_persons = config.get(DOMAIN, []) manager = hass.data[DOMAIN] = PersonManager(hass, component, conf_persons) await manager.async_initialize() websocket_api.async_register_command(hass, ws_list_person) websocket_api.async_register_command(hass, ws_create_person) websocket_api.async_register_command(hass, ws_update_person) websocket_api.async_register_command(hass, ws_delete_person) return True
async def _async_setup_platform(hass: HomeAssistantType, config: ConfigType, async_add_entities, discovery_info): """Set up the cast platform.""" import pychromecast # Import CEC IGNORE attributes pychromecast.IGNORE_CEC += config.get(CONF_IGNORE_CEC, []) hass.data.setdefault(ADDED_CAST_DEVICES_KEY, set()) hass.data.setdefault(KNOWN_CHROMECAST_INFO_KEY, set()) info = None if discovery_info is not None: info = ChromecastInfo(host=discovery_info['host'], port=discovery_info['port']) elif CONF_HOST in config: info = ChromecastInfo(host=config[CONF_HOST], port=DEFAULT_PORT) @callback def async_cast_discovered(discover: ChromecastInfo) -> None: """Handle discovery of a new chromecast.""" if info is not None and info.host_port != discover.host_port: # Not our requested cast device. return cast_device = _async_create_cast_device(hass, discover) if cast_device is not None: async_add_entities([cast_device]) remove_handler = async_dispatcher_connect( hass, SIGNAL_CAST_DISCOVERED, async_cast_discovered) # Re-play the callback for all past chromecasts, store the objects in # a list to avoid concurrent modification resulting in exception. for chromecast in list(hass.data[KNOWN_CHROMECAST_INFO_KEY]): async_cast_discovered(chromecast) if info is None or info.is_audio_group: # If we were a) explicitly told to enable discovery or # b) have an audio group cast device, we need internal discovery. hass.async_add_job(_setup_internal_discovery, hass) else: info = await hass.async_add_job(_fill_out_missing_chromecast_info, info) if info.friendly_name is None: _LOGGER.debug("Cannot retrieve detail information for chromecast" " %s, the device may not be online", info) remove_handler() raise PlatformNotReady hass.async_add_job(_discover_chromecast, hass, info)
async def _async_setup_server(hass: HomeAssistantType, config: ConfigType): """Try to start embedded MQTT broker. This method is a coroutine. """ conf = config.get(DOMAIN, {}) # type: ConfigType success, broker_config = \ await server.async_start( hass, conf.get(CONF_PASSWORD), conf.get(CONF_EMBEDDED)) if not success: return None return broker_config
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: """Start the MQTT protocol service.""" conf = config.get(DOMAIN) # type: Optional[ConfigType] # We need this because discovery can cause components to be set up and # otherwise it will not load the users config. # This needs a better solution. hass.data[DATA_MQTT_HASS_CONFIG] = config websocket_api.async_register_command(hass, websocket_subscribe) if conf is None: # If we have a config entry, setup is done by that config entry. # If there is no config entry, this should fail. return bool(hass.config_entries.async_entries(DOMAIN)) conf = dict(conf) if CONF_EMBEDDED in conf or CONF_BROKER not in conf: broker_config = await _async_setup_server(hass, config) if broker_config is None: _LOGGER.error("Unable to start embedded MQTT broker") return False conf.update({ CONF_BROKER: broker_config[0], CONF_PORT: broker_config[1], CONF_USERNAME: broker_config[2], CONF_PASSWORD: broker_config[3], CONF_CERTIFICATE: broker_config[4], CONF_PROTOCOL: broker_config[5], CONF_CLIENT_KEY: None, CONF_CLIENT_CERT: None, CONF_TLS_INSECURE: None, }) hass.data[DATA_MQTT_CONFIG] = conf # Only import if we haven't before. if not hass.config_entries.async_entries(DOMAIN): hass.async_create_task(hass.config_entries.flow.async_init( DOMAIN, context={'source': config_entries.SOURCE_IMPORT}, data={} )) return True
def async_template_from_config(config: ConfigType, config_validation: bool = True) \ -> Callable[..., bool]: """Wrap action method with state based condition.""" if config_validation: config = cv.TEMPLATE_CONDITION_SCHEMA(config) value_template = cast(Template, config.get(CONF_VALUE_TEMPLATE)) def template_if(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool: """Validate template based if-condition.""" value_template.hass = hass return async_template(hass, value_template, variables) return template_if
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the HomematicIP Cloud component.""" hass.data[DOMAIN] = {} accesspoints = config.get(DOMAIN, []) for conf in accesspoints: if conf[CONF_ACCESSPOINT] not in configured_haps(hass): hass.async_add_job(hass.config_entries.flow.async_init( DOMAIN, context={'source': config_entries.SOURCE_IMPORT}, data={ HMIPC_HAPID: conf[CONF_ACCESSPOINT], HMIPC_AUTHTOKEN: conf[CONF_AUTHTOKEN], HMIPC_NAME: conf[CONF_NAME], } )) return True
async def _async_setup_discovery(hass: HomeAssistantType, config: ConfigType) -> bool: """Try to start the discovery of MQTT devices. This method is a coroutine. """ conf = config.get(DOMAIN, {}) # type: ConfigType discovery = await async_prepare_setup_platform( hass, config, DOMAIN, 'discovery') if discovery is None: _LOGGER.error("Unable to load MQTT discovery") return False success = await discovery.async_start( hass, conf[CONF_DISCOVERY_PREFIX], config) # type: bool return success
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Setup the recorder.""" conf = config.get(DOMAIN, {}) purge_days = conf.get(CONF_PURGE_DAYS) db_url = conf.get(CONF_DB_URL, None) if not db_url: db_url = DEFAULT_URL.format( hass_config_path=hass.config.path(DEFAULT_DB_FILE)) include = conf.get(CONF_INCLUDE, {}) exclude = conf.get(CONF_EXCLUDE, {}) instance = hass.data[DATA_INSTANCE] = Recorder( hass, purge_days=purge_days, uri=db_url, include=include, exclude=exclude) instance.async_initialize() instance.start() return (yield from instance.async_db_ready)
def async_setup(hass: HomeAssistantType, config: ConfigType): """Set up the device tracker.""" yaml_path = hass.config.path(YAML_DEVICES) conf = config.get(DOMAIN, []) conf = conf[0] if conf else {} consider_home = conf.get(CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME) track_new = conf.get(CONF_TRACK_NEW, DEFAULT_TRACK_NEW) devices = yield from async_load_config(yaml_path, hass, consider_home) tracker = DeviceTracker(hass, consider_home, track_new, devices) @asyncio.coroutine def async_setup_platform(p_type, p_config, disc_info=None): """Set up a device tracker platform.""" platform = yield from async_prepare_setup_platform( hass, config, DOMAIN, p_type) if platform is None: return _LOGGER.info("Setting up %s.%s", DOMAIN, p_type) try: scanner = None setup = None if hasattr(platform, 'async_get_scanner'): scanner = yield from platform.async_get_scanner( hass, {DOMAIN: p_config}) elif hasattr(platform, 'get_scanner'): scanner = yield from hass.async_add_job( platform.get_scanner, hass, {DOMAIN: p_config}) elif hasattr(platform, 'async_setup_scanner'): setup = yield from platform.async_setup_scanner( hass, p_config, tracker.async_see, disc_info) elif hasattr(platform, 'setup_scanner'): setup = yield from hass.async_add_job(platform.setup_scanner, hass, p_config, tracker.see, disc_info) else: raise HomeAssistantError("Invalid device_tracker platform.") if scanner: async_setup_scanner_platform(hass, p_config, scanner, tracker.async_see, p_type) return if not setup: _LOGGER.error("Error setting up platform %s", p_type) return except Exception: # pylint: disable=broad-except _LOGGER.exception("Error setting up platform %s", p_type) setup_tasks = [ async_setup_platform(p_type, p_config) for p_type, p_config in config_per_platform(config, DOMAIN) ] if setup_tasks: yield from asyncio.wait(setup_tasks, loop=hass.loop) tracker.async_setup_group() @asyncio.coroutine def async_platform_discovered(platform, info): """Load a platform.""" yield from async_setup_platform(platform, {}, disc_info=info) discovery.async_listen_platform(hass, DOMAIN, async_platform_discovered) # Clean up stale devices async_track_utc_time_change(hass, tracker.async_update_stale, second=range(0, 60, 5)) @asyncio.coroutine def async_see_service(call): """Service to see a device.""" args = { key: value for key, value in call.data.items() if key in (ATTR_MAC, ATTR_DEV_ID, ATTR_HOST_NAME, ATTR_LOCATION_NAME, ATTR_GPS, ATTR_GPS_ACCURACY, ATTR_BATTERY, ATTR_ATTRIBUTES) } yield from tracker.async_see(**args) descriptions = yield from hass.async_add_job( load_yaml_config_file, os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.async_register(DOMAIN, SERVICE_SEE, async_see_service, descriptions.get(SERVICE_SEE)) # restore yield from tracker.async_setup_tracked_device() return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up Meteo-France from legacy config file.""" if not (conf := config.get(DOMAIN)): return True
def setup_services( hass: HomeAssistant, hass_config: ConfigType, config: ConfigType, track_new_found_calendars: bool, calendar_service: GoogleCalendarService, ) -> None: """Set up the service listeners.""" def _found_calendar(call: ServiceCall) -> None: """Check if we know about a calendar and generate PLATFORM_DISCOVER.""" calendar = get_calendar_info(hass, call.data) if hass.data[DATA_INDEX].get(calendar[CONF_CAL_ID]) is not None: return hass.data[DATA_INDEX].update({calendar[CONF_CAL_ID]: calendar}) update_config( hass.config.path(YAML_DEVICES), hass.data[DATA_INDEX][calendar[CONF_CAL_ID]] ) discovery.load_platform( hass, Platform.CALENDAR, DOMAIN, hass.data[DATA_INDEX][calendar[CONF_CAL_ID]], hass_config, ) hass.services.register(DOMAIN, SERVICE_FOUND_CALENDARS, _found_calendar) def _scan_for_calendars(call: ServiceCall) -> None: """Scan for new calendars.""" service = calendar_service.get() cal_list = service.calendarList() calendars = cal_list.list().execute()["items"] for calendar in calendars: calendar["track"] = track_new_found_calendars hass.services.call(DOMAIN, SERVICE_FOUND_CALENDARS, calendar) hass.services.register(DOMAIN, SERVICE_SCAN_CALENDARS, _scan_for_calendars) def _add_event(call: ServiceCall) -> None: """Add a new event to calendar.""" service = calendar_service.get() start = {} end = {} if EVENT_IN in call.data: if EVENT_IN_DAYS in call.data[EVENT_IN]: now = datetime.now() start_in = now + timedelta(days=call.data[EVENT_IN][EVENT_IN_DAYS]) end_in = start_in + timedelta(days=1) start = {"date": start_in.strftime("%Y-%m-%d")} end = {"date": end_in.strftime("%Y-%m-%d")} elif EVENT_IN_WEEKS in call.data[EVENT_IN]: now = datetime.now() start_in = now + timedelta(weeks=call.data[EVENT_IN][EVENT_IN_WEEKS]) end_in = start_in + timedelta(days=1) start = {"date": start_in.strftime("%Y-%m-%d")} end = {"date": end_in.strftime("%Y-%m-%d")} elif EVENT_START_DATE in call.data: start = {"date": str(call.data[EVENT_START_DATE])} end = {"date": str(call.data[EVENT_END_DATE])} elif EVENT_START_DATETIME in call.data: start_dt = str( call.data[EVENT_START_DATETIME].strftime("%Y-%m-%dT%H:%M:%S") ) end_dt = str(call.data[EVENT_END_DATETIME].strftime("%Y-%m-%dT%H:%M:%S")) start = {"dateTime": start_dt, "timeZone": str(hass.config.time_zone)} end = {"dateTime": end_dt, "timeZone": str(hass.config.time_zone)} event = { "summary": call.data[EVENT_SUMMARY], "description": call.data[EVENT_DESCRIPTION], "start": start, "end": end, } service_data = {"calendarId": call.data[EVENT_CALENDAR_ID], "body": event} event = service.events().insert(**service_data).execute() # Only expose the add event service if we have the correct permissions if config.get(CONF_CALENDAR_ACCESS) is FeatureAccess.read_write: hass.services.register( DOMAIN, SERVICE_ADD_EVENT, _add_event, schema=ADD_EVENT_SERVICE_SCHEMA )
async def async_attach_trigger( hass: HomeAssistant, config: ConfigType, action: AutomationActionType, automation_info: AutomationTriggerInfo, *, platform_type: str = "template", ) -> CALLBACK_TYPE: """Listen for state changes based on configuration.""" trigger_data = automation_info["trigger_data"] value_template: Template = config[CONF_VALUE_TEMPLATE] value_template.hass = hass time_delta = config.get(CONF_FOR) template.attach(hass, time_delta) delay_cancel = None job = HassJob(action) armed = False # Arm at setup if the template is already false. try: if not result_as_boolean( value_template.async_render(automation_info["variables"])): armed = True except exceptions.TemplateError as ex: _LOGGER.warning( "Error initializing 'template' trigger for '%s': %s", automation_info["name"], ex, ) @callback def template_listener(event, updates): """Listen for state changes and calls action.""" nonlocal delay_cancel, armed result = updates.pop().result if isinstance(result, exceptions.TemplateError): _LOGGER.warning( "Error evaluating 'template' trigger for '%s': %s", automation_info["name"], result, ) return if delay_cancel: # pylint: disable=not-callable delay_cancel() delay_cancel = None if not result_as_boolean(result): armed = True return # Only fire when previously armed. if not armed: return # Fire! armed = False entity_id = event and event.data.get("entity_id") from_s = event and event.data.get("old_state") to_s = event and event.data.get("new_state") if entity_id is not None: description = f"{entity_id} via template" else: description = "time change or manual update via template" template_variables = { "platform": platform_type, "entity_id": entity_id, "from_state": from_s, "to_state": to_s, } trigger_variables = { **trigger_data, "for": time_delta, "description": description, } @callback def call_action(*_): """Call action with right context.""" nonlocal trigger_variables hass.async_run_hass_job( job, {"trigger": { **template_variables, **trigger_variables }}, (to_s.context if to_s else None), ) if not time_delta: call_action() return try: period = cv.positive_time_period( template.render_complex(time_delta, {"trigger": template_variables})) except (exceptions.TemplateError, vol.Invalid) as ex: _LOGGER.error("Error rendering '%s' for template: %s", automation_info["name"], ex) return trigger_variables["for"] = period delay_cancel = async_call_later(hass, period.total_seconds(), call_action) info = async_track_template_result( hass, [TrackTemplate(value_template, automation_info["variables"])], template_listener, ) unsub = info.async_remove @callback def async_remove(): """Remove state listeners async.""" unsub() if delay_cancel: # pylint: disable=not-callable delay_cancel() return async_remove
async def async_from_config_dict( config: ConfigType, hass: core.HomeAssistant ) -> core.HomeAssistant | None: """Try to configure Home Assistant from a configuration dictionary. Dynamically loads required components and its dependencies. This method is a coroutine. """ start = monotonic() hass.config_entries = config_entries.ConfigEntries(hass, config) await hass.config_entries.async_initialize() # Set up core. _LOGGER.debug("Setting up %s", CORE_INTEGRATIONS) if not all( await asyncio.gather( *( async_setup_component(hass, domain, config) for domain in CORE_INTEGRATIONS ) ) ): _LOGGER.error("Home Assistant core failed to initialize. ") return None _LOGGER.debug("Home Assistant core initialized") core_config = config.get(core.DOMAIN, {}) try: await conf_util.async_process_ha_core_config(hass, core_config) except vol.Invalid as config_err: conf_util.async_log_exception(config_err, "homeassistant", core_config, hass) return None except HomeAssistantError: _LOGGER.error( "Home Assistant core failed to initialize. " "Further initialization aborted" ) return None await _async_set_up_integrations(hass, config) stop = monotonic() _LOGGER.info("Home Assistant initialized in %.2fs", stop - start) if REQUIRED_NEXT_PYTHON_DATE and sys.version_info[:3] < REQUIRED_NEXT_PYTHON_VER: msg = ( "Support for the running Python version " f"{'.'.join(str(x) for x in sys.version_info[:3])} is deprecated and will " f"be removed in the first release after {REQUIRED_NEXT_PYTHON_DATE}. " "Please upgrade Python to " f"{'.'.join(str(x) for x in REQUIRED_NEXT_PYTHON_VER)} or " "higher." ) _LOGGER.warning(msg) hass.components.persistent_notification.async_create( msg, "Python version", "python_version" ) return hass
def setup_platform( hass: HomeAssistant, config: ConfigType, add_entities: AddEntitiesCallback, discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the aREST sensor.""" resource = config[CONF_RESOURCE] var_conf = config[CONF_MONITORED_VARIABLES] pins = config[CONF_PINS] try: response = requests.get(resource, timeout=10).json() except requests.exceptions.MissingSchema: _LOGGER.error( "Missing resource or schema in configuration. Add http:// to your URL" ) return except requests.exceptions.ConnectionError: _LOGGER.error("No route to device at %s", resource) return arest = ArestData(resource) def make_renderer(value_template): """Create a renderer based on variable_template value.""" if value_template is None: return lambda value: value value_template.hass = hass def _render(value): try: return value_template.async_render({"value": value}, parse_result=False) except TemplateError: _LOGGER.exception("Error parsing value") return value return _render dev = [] if var_conf is not None: for variable, var_data in var_conf.items(): if variable not in response["variables"]: _LOGGER.error("Variable: %s does not exist", variable) continue renderer = make_renderer(var_data.get(CONF_VALUE_TEMPLATE)) dev.append( ArestSensor( arest, resource, config.get(CONF_NAME, response[CONF_NAME]), var_data.get(CONF_NAME, variable), variable=variable, unit_of_measurement=var_data.get(CONF_UNIT_OF_MEASUREMENT), renderer=renderer, )) if pins is not None: for pinnum, pin in pins.items(): renderer = make_renderer(pin.get(CONF_VALUE_TEMPLATE)) dev.append( ArestSensor( ArestData(resource, pinnum), resource, config.get(CONF_NAME, response[CONF_NAME]), pin.get(CONF_NAME), pin=pinnum, unit_of_measurement=pin.get(CONF_UNIT_OF_MEASUREMENT), renderer=renderer, )) add_entities(dev, True)
async def async_setup(hass: HomeAssistantType, config: ConfigType): """Set up the device tracker.""" yaml_path = hass.config.path(YAML_DEVICES) conf = config.get(DOMAIN, []) conf = conf[0] if conf else {} consider_home = conf.get(CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME) defaults = conf.get(CONF_NEW_DEVICE_DEFAULTS, {}) track_new = conf.get(CONF_TRACK_NEW) if track_new is None: track_new = defaults.get(CONF_TRACK_NEW, DEFAULT_TRACK_NEW) devices = await async_load_config(yaml_path, hass, consider_home) tracker = DeviceTracker(hass, consider_home, track_new, defaults, devices) async def async_setup_platform(p_type, p_config, disc_info=None): """Set up a device tracker platform.""" platform = await async_prepare_setup_platform(hass, config, DOMAIN, p_type) if platform is None: return _LOGGER.info("Setting up %s.%s", DOMAIN, p_type) try: scanner = None setup = None if hasattr(platform, 'async_get_scanner'): scanner = await platform.async_get_scanner( hass, {DOMAIN: p_config}) elif hasattr(platform, 'get_scanner'): scanner = await hass.async_add_job(platform.get_scanner, hass, {DOMAIN: p_config}) elif hasattr(platform, 'async_setup_scanner'): setup = await platform.async_setup_scanner( hass, p_config, tracker.async_see, disc_info) elif hasattr(platform, 'setup_scanner'): setup = await hass.async_add_job(platform.setup_scanner, hass, p_config, tracker.see, disc_info) else: raise HomeAssistantError("Invalid device_tracker platform.") if scanner: async_setup_scanner_platform(hass, p_config, scanner, tracker.async_see, p_type) return if not setup: _LOGGER.error("Error setting up platform %s", p_type) return except Exception: # pylint: disable=broad-except _LOGGER.exception("Error setting up platform %s", p_type) setup_tasks = [ async_setup_platform(p_type, p_config) for p_type, p_config in config_per_platform(config, DOMAIN) ] if setup_tasks: await asyncio.wait(setup_tasks, loop=hass.loop) tracker.async_setup_group() async def async_platform_discovered(platform, info): """Load a platform.""" await async_setup_platform(platform, {}, disc_info=info) discovery.async_listen_platform(hass, DOMAIN, async_platform_discovered) # Clean up stale devices async_track_utc_time_change(hass, tracker.async_update_stale, second=range(0, 60, 5)) async def async_see_service(call): """Service to see a device.""" # Temp workaround for iOS, introduced in 0.65 data = dict(call.data) data.pop('hostname', None) data.pop('battery_status', None) await tracker.async_see(**data) hass.services.async_register(DOMAIN, SERVICE_SEE, async_see_service, SERVICE_SEE_PAYLOAD_SCHEMA) # restore await tracker.async_setup_tracked_device() return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the demo environment.""" if DOMAIN not in config: return True if not hass.config_entries.async_entries(DOMAIN): hass.async_create_task( hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data={})) # Set up demo platforms for platform in COMPONENTS_WITH_DEMO_PLATFORM: hass.async_create_task( hass.helpers.discovery.async_load_platform(platform, DOMAIN, {}, config)) config.setdefault(ha.DOMAIN, {}) config.setdefault(DOMAIN, {}) # Set up sun if not hass.config.latitude: hass.config.latitude = 32.87336 if not hass.config.longitude: hass.config.longitude = 117.22743 tasks = [setup.async_setup_component(hass, "sun", config)] # Set up input select tasks.append( setup.async_setup_component( hass, "input_select", { "input_select": { "living_room_preset": { "options": ["Visitors", "Visitors with kids", "Home Alone"] }, "who_cooks": { "icon": "mdi:panda", "initial": "Anne Therese", "name": "Cook today", "options": ["Paulus", "Anne Therese"], }, } }, )) # Set up input boolean tasks.append( setup.async_setup_component( hass, "input_boolean", { "input_boolean": { "notify": { "icon": "mdi:car", "initial": False, "name": "Notify Anne Therese is home", } } }, )) # Set up input button tasks.append( setup.async_setup_component( hass, "input_button", { "input_button": { "bell": { "icon": "mdi:bell-ring-outline", "name": "Ring bell", } } }, )) # Set up input number tasks.append( setup.async_setup_component( hass, "input_number", { "input_number": { "noise_allowance": { "icon": "mdi:bell-ring", "min": 0, "max": 10, "name": "Allowed Noise", "unit_of_measurement": SOUND_PRESSURE_DB, } } }, )) results = await asyncio.gather(*tasks) if any(not result for result in results): return False # Set up example persistent notification persistent_notification.async_create( hass, "This is an example of a persistent notification.", title="Example Notification", ) async def demo_start_listener(_event): """Finish set up.""" await finish_setup(hass, config) hass.bus.async_listen(EVENT_HOMEASSISTANT_START, demo_start_listener) return True
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: """Set up an input select.""" component = EntityComponent(_LOGGER, DOMAIN, hass) id_manager = collection.IDManager() yaml_collection = collection.YamlCollection( logging.getLogger(f"{__name__}.yaml_collection"), id_manager) collection.sync_entity_lifecycle(hass, DOMAIN, DOMAIN, component, yaml_collection, InputSelect.from_yaml) storage_collection = InputSelectStorageCollection( Store(hass, STORAGE_VERSION, STORAGE_KEY), logging.getLogger(f"{__name__}.storage_collection"), id_manager, ) collection.sync_entity_lifecycle(hass, DOMAIN, DOMAIN, component, storage_collection, InputSelect) await yaml_collection.async_load([{ CONF_ID: id_, **cfg } for id_, cfg in config.get(DOMAIN, {}).items()]) await storage_collection.async_load() collection.StorageCollectionWebsocket(storage_collection, DOMAIN, DOMAIN, CREATE_FIELDS, UPDATE_FIELDS).async_setup(hass) async def reload_service_handler(service_call: ServiceCallType) -> None: """Reload yaml entities.""" conf = await component.async_prepare_reload(skip_reset=True) if conf is None: conf = {DOMAIN: {}} await yaml_collection.async_load([{ CONF_ID: id_, **cfg } for id_, cfg in conf.get(DOMAIN, {}).items()]) homeassistant.helpers.service.async_register_admin_service( hass, DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_SCHEMA, ) component.async_register_entity_service( SERVICE_SELECT_OPTION, {vol.Required(ATTR_OPTION): cv.string}, "async_select_option", ) component.async_register_entity_service( SERVICE_SELECT_NEXT, {vol.Optional(ATTR_CYCLE, default=True): bool}, "async_next", ) component.async_register_entity_service( SERVICE_SELECT_PREVIOUS, {vol.Optional(ATTR_CYCLE, default=True): bool}, "async_previous", ) component.async_register_entity_service( SERVICE_SELECT_FIRST, {}, callback(lambda entity, call: entity.async_select_index(0)), ) component.async_register_entity_service( SERVICE_SELECT_LAST, {}, callback(lambda entity, call: entity.async_select_index(-1)), ) component.async_register_entity_service( SERVICE_SET_OPTIONS, { vol.Required(ATTR_OPTIONS): vol.All(cv.ensure_list, vol.Length(min=1), [cv.string]) }, "async_set_options", ) return True
def _create_light(knx_module: XKNX, config: ConfigType) -> XknxLight: """Return a KNX Light device to be used within XKNX.""" group_address_tunable_white = None group_address_tunable_white_state = None group_address_color_temp = None group_address_color_temp_state = None if config[LightSchema.CONF_COLOR_TEMP_MODE] == ColorTempModes.ABSOLUTE: group_address_color_temp = config.get( LightSchema.CONF_COLOR_TEMP_ADDRESS) group_address_color_temp_state = config.get( LightSchema.CONF_COLOR_TEMP_STATE_ADDRESS) elif config[LightSchema.CONF_COLOR_TEMP_MODE] == ColorTempModes.RELATIVE: group_address_tunable_white = config.get( LightSchema.CONF_COLOR_TEMP_ADDRESS) group_address_tunable_white_state = config.get( LightSchema.CONF_COLOR_TEMP_STATE_ADDRESS) ( red_switch, red_switch_state, red_brightness, red_brightness_state, ) = _create_light_color(LightSchema.CONF_RED, config) ( green_switch, green_switch_state, green_brightness, green_brightness_state, ) = _create_light_color(LightSchema.CONF_GREEN, config) ( blue_switch, blue_switch_state, blue_brightness, blue_brightness_state, ) = _create_light_color(LightSchema.CONF_BLUE, config) ( white_switch, white_switch_state, white_brightness, white_brightness_state, ) = _create_light_color(LightSchema.CONF_WHITE, config) return XknxLight( knx_module, name=config[CONF_NAME], group_address_switch=config.get(CONF_ADDRESS), group_address_switch_state=config.get(LightSchema.CONF_STATE_ADDRESS), group_address_brightness=config.get( LightSchema.CONF_BRIGHTNESS_ADDRESS), group_address_brightness_state=config.get( LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS), group_address_color=config.get(LightSchema.CONF_COLOR_ADDRESS), group_address_color_state=config.get( LightSchema.CONF_COLOR_STATE_ADDRESS), group_address_rgbw=config.get(LightSchema.CONF_RGBW_ADDRESS), group_address_rgbw_state=config.get( LightSchema.CONF_RGBW_STATE_ADDRESS), group_address_tunable_white=group_address_tunable_white, group_address_tunable_white_state=group_address_tunable_white_state, group_address_color_temperature=group_address_color_temp, group_address_color_temperature_state=group_address_color_temp_state, group_address_switch_red=red_switch, group_address_switch_red_state=red_switch_state, group_address_brightness_red=red_brightness, group_address_brightness_red_state=red_brightness_state, group_address_switch_green=green_switch, group_address_switch_green_state=green_switch_state, group_address_brightness_green=green_brightness, group_address_brightness_green_state=green_brightness_state, group_address_switch_blue=blue_switch, group_address_switch_blue_state=blue_switch_state, group_address_brightness_blue=blue_brightness, group_address_brightness_blue_state=blue_brightness_state, group_address_switch_white=white_switch, group_address_switch_white_state=white_switch_state, group_address_brightness_white=white_brightness, group_address_brightness_white_state=white_brightness_state, min_kelvin=config[LightSchema.CONF_MIN_KELVIN], max_kelvin=config[LightSchema.CONF_MAX_KELVIN], )
def _create_climate(knx_module: XKNX, config: ConfigType) -> XknxClimate: """Return a KNX Climate device to be used within XKNX.""" climate_mode = XknxClimateMode( knx_module, name=f"{config[CONF_NAME]} Mode", group_address_operation_mode=config.get( ClimateSchema.CONF_OPERATION_MODE_ADDRESS), group_address_operation_mode_state=config.get( ClimateSchema.CONF_OPERATION_MODE_STATE_ADDRESS), group_address_controller_status=config.get( ClimateSchema.CONF_CONTROLLER_STATUS_ADDRESS), group_address_controller_status_state=config.get( ClimateSchema.CONF_CONTROLLER_STATUS_STATE_ADDRESS), group_address_controller_mode=config.get( ClimateSchema.CONF_CONTROLLER_MODE_ADDRESS), group_address_controller_mode_state=config.get( ClimateSchema.CONF_CONTROLLER_MODE_STATE_ADDRESS), group_address_operation_mode_protection=config.get( ClimateSchema.CONF_OPERATION_MODE_FROST_PROTECTION_ADDRESS), group_address_operation_mode_night=config.get( ClimateSchema.CONF_OPERATION_MODE_NIGHT_ADDRESS), group_address_operation_mode_comfort=config.get( ClimateSchema.CONF_OPERATION_MODE_COMFORT_ADDRESS), group_address_operation_mode_standby=config.get( ClimateSchema.CONF_OPERATION_MODE_STANDBY_ADDRESS), group_address_heat_cool=config.get( ClimateSchema.CONF_HEAT_COOL_ADDRESS), group_address_heat_cool_state=config.get( ClimateSchema.CONF_HEAT_COOL_STATE_ADDRESS), operation_modes=config.get(ClimateSchema.CONF_OPERATION_MODES), controller_modes=config.get(ClimateSchema.CONF_CONTROLLER_MODES), ) return XknxClimate( knx_module, name=config[CONF_NAME], group_address_temperature=config[ ClimateSchema.CONF_TEMPERATURE_ADDRESS], group_address_target_temperature=config.get( ClimateSchema.CONF_TARGET_TEMPERATURE_ADDRESS), group_address_target_temperature_state=config[ ClimateSchema.CONF_TARGET_TEMPERATURE_STATE_ADDRESS], group_address_setpoint_shift=config.get( ClimateSchema.CONF_SETPOINT_SHIFT_ADDRESS), group_address_setpoint_shift_state=config.get( ClimateSchema.CONF_SETPOINT_SHIFT_STATE_ADDRESS), setpoint_shift_mode=config[ClimateSchema.CONF_SETPOINT_SHIFT_MODE], setpoint_shift_max=config[ClimateSchema.CONF_SETPOINT_SHIFT_MAX], setpoint_shift_min=config[ClimateSchema.CONF_SETPOINT_SHIFT_MIN], temperature_step=config[ClimateSchema.CONF_TEMPERATURE_STEP], group_address_on_off=config.get(ClimateSchema.CONF_ON_OFF_ADDRESS), group_address_on_off_state=config.get( ClimateSchema.CONF_ON_OFF_STATE_ADDRESS), min_temp=config.get(ClimateSchema.CONF_MIN_TEMP), max_temp=config.get(ClimateSchema.CONF_MAX_TEMP), mode=climate_mode, on_off_invert=config[ClimateSchema.CONF_ON_OFF_INVERT], create_temperature_sensors=config.get( ClimateSchema.CONF_CREATE_TEMPERATURE_SENSORS), )
async def async_attach_trigger( hass: HomeAssistant, config: ConfigType, action: TriggerActionType, trigger_info: TriggerInfo, ) -> CALLBACK_TYPE: """Listen for state changes based on configuration.""" trigger_data = trigger_info["trigger_data"] topic = config[CONF_TOPIC] wanted_payload = config.get(CONF_PAYLOAD) value_template = config.get(CONF_VALUE_TEMPLATE) encoding = config[CONF_ENCODING] or None qos = config[CONF_QOS] job = HassJob(action) variables = None if trigger_info: variables = trigger_info.get("variables") template.attach(hass, wanted_payload) if wanted_payload: wanted_payload = wanted_payload.async_render(variables, limited=True, parse_result=False) template.attach(hass, topic) if isinstance(topic, template.Template): topic = topic.async_render(variables, limited=True, parse_result=False) topic = mqtt.util.valid_subscribe_topic(topic) template.attach(hass, value_template) @callback def mqtt_automation_listener(mqttmsg): """Listen for MQTT messages.""" payload = mqttmsg.payload if value_template is not None: payload = value_template.async_render_with_possible_json_value( payload, error_value=None, ) if wanted_payload is None or wanted_payload == payload: data = { **trigger_data, "platform": "mqtt", "topic": mqttmsg.topic, "payload": mqttmsg.payload, "qos": mqttmsg.qos, "description": f"mqtt topic {mqttmsg.topic}", } with suppress(ValueError): data["payload_json"] = json_loads(mqttmsg.payload) hass.async_run_hass_job(job, {"trigger": data}) _LOGGER.debug("Attaching MQTT trigger for topic: '%s', payload: '%s'", topic, wanted_payload) remove = await mqtt.async_subscribe(hass, topic, mqtt_automation_listener, encoding=encoding, qos=qos) return remove
async def async_setup(hass: HomeAssistantType, config: ConfigType): """Setup the Homie service.""" # Init _DEVICES = dict() hass.data[KEY_HOMIE_ALREADY_DISCOVERED] = dict() # Config conf = config.get(DOMAIN) if conf is None: conf = CONFIG_SCHEMA({DOMAIN: {}})[DOMAIN] discovery_prefix = conf.get(CONF_DISCOVERY_PREFIX) qos = conf.get(CONF_QOS) # Destroy Homie # async def async_destroy(event): # # TODO: unsub? # pass # hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_destroy) # Sart async def async_start(): await mqtt.async_subscribe(hass, f'{discovery_prefix}/+/$homie', async_discover_message_received, qos) async def async_discover_message_received(topic: str, payload: str, msg_qos: int): device_match = DISCOVER_DEVICE.match(topic) if device_match and payload == HOMIE_SUPPORTED_VERSION: device_base_topic = device_match.group('prefix_topic') device_id = device_match.group('device_id') if device_id not in _DEVICES: device = HomieDevice(device_base_topic, device_id, async_component_ready) _DEVICES[device_id] = device await device._async_setup(hass, qos) async def async_component_ready(component): if type(component) is HomieDevice: await async_setup_device(component) if type(component) is HomieNode: await async_setup_node(component) async def async_setup_device(device: HomieDevice): pass async def async_setup_node(node: HomieNode): def get_entity_name(): return f"{node.device.device_id}_{node.node_id}" if node.type == 'sensor': await setup_device_node_as_platform(get_entity_name(), node, 'sensor') elif node.type == 'switch': await setup_device_node_as_platform(get_entity_name(), node, 'switch') async def setup_device_node_as_platform(entity_name: str, node: HomieNode, platform: str): hass.data[KEY_HOMIE_ALREADY_DISCOVERED][entity_name] = node discovery_info = {KEY_HOMIE_ENTITY_NAME: entity_name} await async_load_platform(hass, platform, DOMAIN, discovery_info, conf) await async_start() return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up songpal environment.""" if (conf := config.get(DOMAIN)) is None: return True
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: """Set up Huawei LTE component.""" # dicttoxml (used by huawei-lte-api) has uselessly verbose INFO level. # https://github.com/quandyfactory/dicttoxml/issues/60 logging.getLogger("dicttoxml").setLevel(logging.WARNING) # Arrange our YAML config to dict with normalized URLs as keys domain_config: dict[str, dict[str, Any]] = {} if DOMAIN not in hass.data: hass.data[DOMAIN] = HuaweiLteData(hass_config=config, config=domain_config) for router_config in config.get(DOMAIN, []): domain_config[url_normalize(router_config.pop(CONF_URL))] = router_config def service_handler(service: ServiceCall) -> None: """Apply a service.""" url = service.data.get(CONF_URL) routers = hass.data[DOMAIN].routers if url: router = routers.get(url) elif not routers: _LOGGER.error("%s: no routers configured", service.service) return elif len(routers) == 1: router = next(iter(routers.values())) else: _LOGGER.error( "%s: more than one router configured, must specify one of URLs %s", service.service, sorted(routers), ) return if not router: _LOGGER.error("%s: router %s unavailable", service.service, url) return if service.service == SERVICE_CLEAR_TRAFFIC_STATISTICS: if router.suspended: _LOGGER.debug("%s: ignored, integration suspended", service.service) return result = router.client.monitoring.set_clear_traffic() _LOGGER.debug("%s: %s", service.service, result) elif service.service == SERVICE_REBOOT: if router.suspended: _LOGGER.debug("%s: ignored, integration suspended", service.service) return result = router.client.device.reboot() _LOGGER.debug("%s: %s", service.service, result) elif service.service == SERVICE_RESUME_INTEGRATION: # Login will be handled automatically on demand router.suspended = False _LOGGER.debug("%s: %s", service.service, "done") elif service.service == SERVICE_SUSPEND_INTEGRATION: router.logout() router.suspended = True _LOGGER.debug("%s: %s", service.service, "done") else: _LOGGER.error("%s: unsupported service", service.service) for service in ADMIN_SERVICES: hass.helpers.service.async_register_admin_service( DOMAIN, service, service_handler, schema=SERVICE_SCHEMA, ) for url, router_config in domain_config.items(): hass.async_create_task( hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_IMPORT}, data={ CONF_URL: url, CONF_USERNAME: router_config.get(CONF_USERNAME), CONF_PASSWORD: router_config.get(CONF_PASSWORD), }, ) ) return True
def __init__(self, config: ConfigType) -> None: """Initialize a boolean input.""" self._config = config self.editable = True self._attr_is_on = config.get(CONF_INITIAL, False) self._attr_unique_id = config[CONF_ID]
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Configure Gammu state machine.""" hass.data.setdefault(DOMAIN, {}) if not (sms_config := config.get(DOMAIN, {})): return True
def setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the ISY 994 platform.""" isy_config = config.get(DOMAIN) user = isy_config.get(CONF_USERNAME) password = isy_config.get(CONF_PASSWORD) tls_version = isy_config.get(CONF_TLS_VER) host = urlparse(isy_config.get(CONF_HOST)) port = host.port addr = host.geturl() hidden_identifier = isy_config.get(CONF_HIDDEN_STRING, DEFAULT_HIDDEN_STRING) sensor_identifier = isy_config.get(CONF_SENSOR_STRING, DEFAULT_SENSOR_STRING) global HIDDEN_STRING HIDDEN_STRING = hidden_identifier if host.scheme == 'http': addr = addr.replace('http://', '') https = False elif host.scheme == 'https': addr = addr.replace('https://', '') https = True else: _LOGGER.error("isy994 host value in configuration is invalid") return False addr = addr.replace(':{}'.format(port), '') import PyISY global PYISY PYISY = PyISY # Connect to ISY controller. global ISY ISY = PyISY.ISY(addr, port, username=user, password=password, use_https=https, tls_ver=tls_version, log=_LOGGER) if not ISY.connected: return False _categorize_nodes(hidden_identifier, sensor_identifier) _categorize_programs() if ISY.configuration.get('Weather Information'): _categorize_weather() # Listen for HA stop to disconnect. hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop) # Load platforms for the devices in the ISY controller that we support. for component in SUPPORTED_DOMAINS: discovery.load_platform(hass, component, DOMAIN, {}, config) ISY.auto_update = True return True
def import_lcn_config(lcn_config: ConfigType) -> list[ConfigType]: """Convert lcn settings from configuration.yaml to config_entries data. Create a list of config_entry data structures like: "data": { "host": "pchk", "ip_address": "192.168.2.41", "port": 4114, "username": "******", "password": "******"sk_num_tries: 0, "dim_mode: "STEPS200", "devices": [ { "address": (0, 7, False) "name": "", "hardware_serial": -1, "software_serial": -1, "hardware_type": -1 }, ... ], "entities": [ { "address": (0, 7, False) "name": "Light_Output1", "resource": "output1", "domain": "light", "domain_data": { "output": "OUTPUT1", "dimmable": True, "transition": 5000.0 } }, ... ] } """ data = {} for connection in lcn_config[CONF_CONNECTIONS]: host = { CONF_HOST: connection[CONF_NAME], CONF_IP_ADDRESS: connection[CONF_HOST], CONF_PORT: connection[CONF_PORT], CONF_USERNAME: connection[CONF_USERNAME], CONF_PASSWORD: connection[CONF_PASSWORD], CONF_SK_NUM_TRIES: connection[CONF_SK_NUM_TRIES], CONF_DIM_MODE: connection[CONF_DIM_MODE], CONF_DEVICES: [], CONF_ENTITIES: [], } data[connection[CONF_NAME]] = host for confkey, domain_config in lcn_config.items(): if confkey == CONF_CONNECTIONS: continue domain = DOMAIN_LOOKUP[confkey] # loop over entities in configuration.yaml for domain_data in domain_config: # remove name and address from domain_data entity_name = domain_data.pop(CONF_NAME) address, host_name = domain_data.pop(CONF_ADDRESS) if host_name is None: host_name = DEFAULT_NAME # check if we have a new device config for device_config in data[host_name][CONF_DEVICES]: if address == device_config[CONF_ADDRESS]: break else: # create new device_config device_config = { CONF_ADDRESS: address, CONF_NAME: "", CONF_HARDWARE_SERIAL: -1, CONF_SOFTWARE_SERIAL: -1, CONF_HARDWARE_TYPE: -1, } data[host_name][CONF_DEVICES].append(device_config) # insert entity config resource = get_resource(domain, domain_data).lower() for entity_config in data[host_name][CONF_ENTITIES]: if (address == entity_config[CONF_ADDRESS] and resource == entity_config[CONF_RESOURCE] and domain == entity_config[CONF_DOMAIN]): break else: # create new entity_config entity_config = { CONF_ADDRESS: address, CONF_NAME: entity_name, CONF_RESOURCE: resource, CONF_DOMAIN: domain, CONF_DOMAIN_DATA: domain_data.copy(), } data[host_name][CONF_ENTITIES].append(entity_config) return list(data.values())
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: conf = config.get(DOMAIN, {}) # type: ConfigType if conf is None: # If we have a config entry, setup is done by that config entry. # If there is no config entry, this should fail. return bool(hass.config_entries.async_entries(DOMAIN)) hass.data[DATA_AIHOME_CONFIG] = conf # Only import if we haven't before. if not hass.config_entries.async_entries(DOMAIN): hass.async_create_task( hass.config_entries.flow.async_init( DOMAIN, context={'source': config_entries.SOURCE_IMPORT}, data={})) if CONF_HTTP in conf: if conf.get(CONF_HTTP) is None: conf[CONF_HTTP] = HTTP_SCHEMA({}) hass.http.register_view(AihomeGateView(hass)) hass.http.register_view( AihomeAuthView( hass, conf.get(CONF_HTTP, {}).get(CONF_HA_URL, hass.config.api.base_url))) global EXPIRATION EXPIRATION = timedelta(hours=conf.get(CONF_HTTP).get( CONF_EXPIRE_IN_HOURS, DEFAULT_EXPIRE_IN_HOURS)) _LOGGER.info('[init] aihome run with "http mode"(mode 1)') MODE.append('http') if CONF_HTTP_PROXY in conf: if conf.get(CONF_HTTP_PROXY) is None: conf[CONF_HTTP_PROXY] = HTTP_PROXY({}) _LOGGER.info('[init] aihome run with "http_proxy mode"(mode 2)') if CONF_SETTING not in conf: _LOGGER.error( '[init] fail to start aihome: http_proxy mode require mqtt congfiguration' ) return False MODE.append('http_proxy') if CONF_SKILL in conf: if conf.get(CONF_SKILL) is None: conf[CONF_SKILL] = SKILL_SCHEMA({}) _LOGGER.info('[init] aihome run with "skill mode"(mode 3)') if CONF_SETTING not in conf: _LOGGER.error( '[init] fail to start aihome: skil mode require mqtt congfiguration' ) return False MODE.append('skill') aihome_util.ENTITY_KEY = conf.get(CONF_SETTING, {}).get(CONF_ENTITY_KEY) aihome_util.CONTEXT_AIHOME = Context( conf.get(CONF_SETTING, {}).get(CONF_USER_ID)) platform = conf[CONF_PLATFORM] manager = hass.data[DATA_AIHOME_BIND_MANAGER] = aihome_util.BindManager( hass, platform) await manager.async_load() for p in platform: try: module = importlib.import_module('custom_components.{}.{}'.format( DOMAIN, p)) _LOGGER.info('[init] import %s.%s', DOMAIN, p) HANDLER[p] = module.createHandler(hass) except ImportError: _LOGGER.error('[init] Unable to import %s.%s', DOMAIN, p) return False return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the HTTP API and debug interface.""" conf: ConfData | None = config.get(DOMAIN) if conf is None: conf = cast(ConfData, HTTP_SCHEMA({})) server_host = conf.get(CONF_SERVER_HOST) server_port = conf[CONF_SERVER_PORT] ssl_certificate = conf.get(CONF_SSL_CERTIFICATE) ssl_peer_certificate = conf.get(CONF_SSL_PEER_CERTIFICATE) ssl_key = conf.get(CONF_SSL_KEY) cors_origins = conf[CONF_CORS_ORIGINS] use_x_forwarded_for = conf.get(CONF_USE_X_FORWARDED_FOR, False) trusted_proxies = conf.get(CONF_TRUSTED_PROXIES) or [] is_ban_enabled = conf[CONF_IP_BAN_ENABLED] login_threshold = conf[CONF_LOGIN_ATTEMPTS_THRESHOLD] ssl_profile = conf[CONF_SSL_PROFILE] server = HomeAssistantHTTP( hass, server_host=server_host, server_port=server_port, ssl_certificate=ssl_certificate, ssl_peer_certificate=ssl_peer_certificate, ssl_key=ssl_key, cors_origins=cors_origins, use_x_forwarded_for=use_x_forwarded_for, trusted_proxies=trusted_proxies, login_threshold=login_threshold, is_ban_enabled=is_ban_enabled, ssl_profile=ssl_profile, ) async def stop_server(event: Event) -> None: """Stop the server.""" await server.stop() async def start_server(*_: Any) -> None: """Start the server.""" with async_start_setup(hass, ["http"]): hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_server) # We already checked it's not None. assert conf is not None await start_http_server_and_save_config(hass, dict(conf), server) async_when_setup_or_start(hass, "frontend", start_server) hass.http = server local_ip = await async_get_source_ip(hass) host = local_ip if server_host is not None: # Assume the first server host name provided as API host host = server_host[0] hass.config.api = ApiConfig(local_ip, host, server_port, ssl_certificate is not None) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the HomematicIP Cloud component.""" hass.data[DOMAIN] = {} accesspoints = config.get(DOMAIN, []) for conf in accesspoints: if conf[CONF_ACCESSPOINT] not in configured_haps(hass): hass.async_add_job( hass.config_entries.flow.async_init( DOMAIN, context={'source': config_entries.SOURCE_IMPORT}, data={ HMIPC_HAPID: conf[CONF_ACCESSPOINT], HMIPC_AUTHTOKEN: conf[CONF_AUTHTOKEN], HMIPC_NAME: conf[CONF_NAME], })) async def _async_activate_eco_mode_with_duration(service): """Service to activate eco mode with duration.""" duration = service.data[ATTR_DURATION] hapid = service.data.get(ATTR_ACCESSPOINT_ID) if hapid: home = _get_home(hapid) if home: await home.activate_absence_with_duration(duration) else: for hapid in hass.data[DOMAIN]: home = hass.data[DOMAIN][hapid].home await home.activate_absence_with_duration(duration) hass.services.async_register(DOMAIN, SERVICE_ACTIVATE_ECO_MODE_WITH_DURATION, _async_activate_eco_mode_with_duration, schema=SCHEMA_ACTIVATE_ECO_MODE_WITH_DURATION) async def _async_activate_eco_mode_with_period(service): """Service to activate eco mode with period.""" endtime = service.data[ATTR_ENDTIME] hapid = service.data.get(ATTR_ACCESSPOINT_ID) if hapid: home = _get_home(hapid) if home: await home.activate_absence_with_period(endtime) else: for hapid in hass.data[DOMAIN]: home = hass.data[DOMAIN][hapid].home await home.activate_absence_with_period(endtime) hass.services.async_register(DOMAIN, SERVICE_ACTIVATE_ECO_MODE_WITH_PERIOD, _async_activate_eco_mode_with_period, schema=SCHEMA_ACTIVATE_ECO_MODE_WITH_PERIOD) async def _async_activate_vacation(service): """Service to activate vacation.""" endtime = service.data[ATTR_ENDTIME] temperature = service.data[ATTR_TEMPERATURE] hapid = service.data.get(ATTR_ACCESSPOINT_ID) if hapid: home = _get_home(hapid) if home: await home.activate_vacation(endtime, temperature) else: for hapid in hass.data[DOMAIN]: home = hass.data[DOMAIN][hapid].home await home.activate_vacation(endtime, temperature) hass.services.async_register(DOMAIN, SERVICE_ACTIVATE_VACATION, _async_activate_vacation, schema=SCHEMA_ACTIVATE_VACATION) async def _async_deactivate_eco_mode(service): """Service to deactivate eco mode.""" hapid = service.data.get(ATTR_ACCESSPOINT_ID) if hapid: home = _get_home(hapid) if home: await home.deactivate_absence() else: for hapid in hass.data[DOMAIN]: home = hass.data[DOMAIN][hapid].home await home.deactivate_absence() hass.services.async_register(DOMAIN, SERVICE_DEACTIVATE_ECO_MODE, _async_deactivate_eco_mode, schema=SCHEMA_DEACTIVATE_ECO_MODE) async def _async_deactivate_vacation(service): """Service to deactivate vacation.""" hapid = service.data.get(ATTR_ACCESSPOINT_ID) if hapid: home = _get_home(hapid) if home: await home.deactivate_vacation() else: for hapid in hass.data[DOMAIN]: home = hass.data[DOMAIN][hapid].home await home.deactivate_vacation() hass.services.async_register(DOMAIN, SERVICE_DEACTIVATE_VACATION, _async_deactivate_vacation, schema=SCHEMA_DEACTIVATE_VACATION) def _get_home(hapid: str): """Return a HmIP home.""" hap = hass.data[DOMAIN][hapid] if hap: return hap.home return None return True
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: """Set up an input select.""" component = EntityComponent(_LOGGER, DOMAIN, hass) id_manager = collection.IDManager() yaml_collection = collection.YamlCollection( logging.getLogger(f"{__name__}.yaml_collection"), id_manager) collection.attach_entity_component_collection(component, yaml_collection, Timer.from_yaml) storage_collection = TimerStorageCollection( Store(hass, STORAGE_VERSION, STORAGE_KEY), logging.getLogger(f"{__name__}.storage_collection"), id_manager, ) collection.attach_entity_component_collection(component, storage_collection, Timer) await yaml_collection.async_load([{ CONF_ID: id_, **cfg } for id_, cfg in config.get(DOMAIN, {}).items()]) await storage_collection.async_load() collection.StorageCollectionWebsocket(storage_collection, DOMAIN, DOMAIN, CREATE_FIELDS, UPDATE_FIELDS).async_setup(hass) collection.attach_entity_registry_cleaner(hass, DOMAIN, DOMAIN, yaml_collection) collection.attach_entity_registry_cleaner(hass, DOMAIN, DOMAIN, storage_collection) async def reload_service_handler(service_call: ServiceCallType) -> None: """Reload yaml entities.""" conf = await component.async_prepare_reload(skip_reset=True) if conf is None: conf = {DOMAIN: {}} await yaml_collection.async_load([{ CONF_ID: id_, **cfg } for id_, cfg in conf.get(DOMAIN, {}).items()]) homeassistant.helpers.service.async_register_admin_service( hass, DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_SCHEMA, ) component.async_register_entity_service( SERVICE_START, { vol.Optional(ATTR_DURATION, default=DEFAULT_DURATION): cv.time_period }, "async_start", ) component.async_register_entity_service(SERVICE_PAUSE, {}, "async_pause") component.async_register_entity_service(SERVICE_CANCEL, {}, "async_cancel") component.async_register_entity_service(SERVICE_FINISH, {}, "async_finish") return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the Withings component.""" conf = config.get(DOMAIN, {}) if not (conf := config.get(DOMAIN, {})): return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the updater component.""" conf = config.get(DOMAIN, {}) for option in (CONF_COMPONENT_REPORTING, CONF_REPORTING): if option in conf: _LOGGER.warning( "Analytics reporting with the option '%s' " "is deprecated and you should remove that from your configuration. " "The analytics part of this integration has moved to the new 'analytics' integration", option, ) async def check_new_version() -> Updater: """Check if a new version is available and report if one is.""" # Skip on dev if "dev" in current_version: return Updater(False, "", "") newest, release_notes = await get_newest_version(hass) _LOGGER.debug("Fetched version %s: %s", newest, release_notes) # Load data from Supervisor if hass.components.hassio.is_hassio(): core_info = hass.components.hassio.get_core_info() newest = core_info["version_latest"] # Validate version update_available = False if AwesomeVersion(newest) > AwesomeVersion(current_version): _LOGGER.debug( "The latest available version of Home Assistant is %s", newest) update_available = True elif AwesomeVersion(newest) == AwesomeVersion(current_version): _LOGGER.debug( "You are on the latest version (%s) of Home Assistant", newest) elif AwesomeVersion(newest) < AwesomeVersion(current_version): _LOGGER.debug( "Local version (%s) is newer than the latest available version (%s)", current_version, newest, ) _LOGGER.debug("Update available: %s", update_available) return Updater(update_available, newest, release_notes) coordinator = hass.data[DOMAIN] = update_coordinator.DataUpdateCoordinator[ Updater]( hass, _LOGGER, name="Home Assistant update", update_method=check_new_version, update_interval=timedelta(days=1), ) # This can take up to 15s which can delay startup asyncio.create_task(coordinator.async_refresh()) hass.async_create_task( discovery.async_load_platform(hass, Platform.BINARY_SENSOR, DOMAIN, {}, config)) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the serving of the frontend.""" await async_setup_frontend_storage(hass) hass.components.websocket_api.async_register_command(websocket_get_panels) hass.components.websocket_api.async_register_command(websocket_get_themes) hass.components.websocket_api.async_register_command( websocket_get_translations) hass.components.websocket_api.async_register_command(websocket_get_version) hass.http.register_view(ManifestJSONView()) conf = config.get(DOMAIN, {}) for key in (CONF_EXTRA_HTML_URL, CONF_EXTRA_HTML_URL_ES5, CONF_JS_VERSION): if key in conf: _LOGGER.error( "Please remove %s from your frontend config. It is no longer supported", key, ) repo_path = conf.get(CONF_FRONTEND_REPO) is_dev = repo_path is not None root_path = _frontend_root(repo_path) for path, should_cache in ( ("service_worker.js", False), ("robots.txt", False), ("onboarding.html", not is_dev), ("static", not is_dev), ("frontend_latest", not is_dev), ("frontend_es5", not is_dev), ): hass.http.register_static_path(f"/{path}", str(root_path / path), should_cache) hass.http.register_static_path("/auth/authorize", str(root_path / "authorize.html"), False) # https://wicg.github.io/change-password-url/ hass.http.register_redirect("/.well-known/change-password", "/profile", redirect_exc=web.HTTPFound) local = hass.config.path("www") if os.path.isdir(local): hass.http.register_static_path("/local", local, not is_dev) hass.http.app.router.register_resource(IndexView(repo_path, hass)) async_register_built_in_panel(hass, "profile") # To smooth transition to new urls, add redirects to new urls of dev tools # Added June 27, 2019. Can be removed in 2021. for panel in ("event", "service", "state", "template"): hass.http.register_redirect(f"/dev-{panel}", f"/developer-tools/{panel}") for panel in ("logs", "info", "mqtt"): # Can be removed in 2021. hass.http.register_redirect(f"/dev-{panel}", f"/config/{panel}") # Added June 20 2020. Can be removed in 2022. hass.http.register_redirect(f"/developer-tools/{panel}", f"/config/{panel}") async_register_built_in_panel( hass, "developer-tools", require_admin=True, sidebar_title="developer_tools", sidebar_icon="hass:hammer", ) hass.data[DATA_EXTRA_MODULE_URL] = UrlManager( conf.get(CONF_EXTRA_MODULE_URL, [])) hass.data[DATA_EXTRA_JS_URL_ES5] = UrlManager( conf.get(CONF_EXTRA_JS_URL_ES5, [])) await _async_setup_themes(hass, conf.get(CONF_THEMES)) return True
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: """Set up the HomematicIP Cloud component.""" hass.data[DOMAIN] = {} accesspoints = config.get(DOMAIN, []) for conf in accesspoints: if conf[CONF_ACCESSPOINT] not in configured_haps(hass): hass.async_add_job( hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data={ HMIPC_HAPID: conf[CONF_ACCESSPOINT], HMIPC_AUTHTOKEN: conf[CONF_AUTHTOKEN], HMIPC_NAME: conf[CONF_NAME], }, )) async def _async_activate_eco_mode_with_duration(service): """Service to activate eco mode with duration.""" duration = service.data[ATTR_DURATION] hapid = service.data.get(ATTR_ACCESSPOINT_ID) if hapid: home = _get_home(hapid) if home: await home.activate_absence_with_duration(duration) else: for hap in hass.data[DOMAIN].values(): await hap.home.activate_absence_with_duration(duration) hass.services.async_register( DOMAIN, SERVICE_ACTIVATE_ECO_MODE_WITH_DURATION, _async_activate_eco_mode_with_duration, schema=SCHEMA_ACTIVATE_ECO_MODE_WITH_DURATION, ) async def _async_activate_eco_mode_with_period(service): """Service to activate eco mode with period.""" endtime = service.data[ATTR_ENDTIME] hapid = service.data.get(ATTR_ACCESSPOINT_ID) if hapid: home = _get_home(hapid) if home: await home.activate_absence_with_period(endtime) else: for hap in hass.data[DOMAIN].values(): await hap.home.activate_absence_with_period(endtime) hass.services.async_register( DOMAIN, SERVICE_ACTIVATE_ECO_MODE_WITH_PERIOD, _async_activate_eco_mode_with_period, schema=SCHEMA_ACTIVATE_ECO_MODE_WITH_PERIOD, ) async def _async_activate_vacation(service): """Service to activate vacation.""" endtime = service.data[ATTR_ENDTIME] temperature = service.data[ATTR_TEMPERATURE] hapid = service.data.get(ATTR_ACCESSPOINT_ID) if hapid: home = _get_home(hapid) if home: await home.activate_vacation(endtime, temperature) else: for hap in hass.data[DOMAIN].values(): await hap.home.activate_vacation(endtime, temperature) hass.services.async_register( DOMAIN, SERVICE_ACTIVATE_VACATION, _async_activate_vacation, schema=SCHEMA_ACTIVATE_VACATION, ) async def _async_deactivate_eco_mode(service): """Service to deactivate eco mode.""" hapid = service.data.get(ATTR_ACCESSPOINT_ID) if hapid: home = _get_home(hapid) if home: await home.deactivate_absence() else: for hap in hass.data[DOMAIN].values(): await hap.home.deactivate_absence() hass.services.async_register( DOMAIN, SERVICE_DEACTIVATE_ECO_MODE, _async_deactivate_eco_mode, schema=SCHEMA_DEACTIVATE_ECO_MODE, ) async def _async_deactivate_vacation(service): """Service to deactivate vacation.""" hapid = service.data.get(ATTR_ACCESSPOINT_ID) if hapid: home = _get_home(hapid) if home: await home.deactivate_vacation() else: for hap in hass.data[DOMAIN].values(): await hap.home.deactivate_vacation() hass.services.async_register( DOMAIN, SERVICE_DEACTIVATE_VACATION, _async_deactivate_vacation, schema=SCHEMA_DEACTIVATE_VACATION, ) async def _set_active_climate_profile(service): """Service to set the active climate profile.""" entity_id_list = service.data[ATTR_ENTITY_ID] climate_profile_index = service.data[ATTR_CLIMATE_PROFILE_INDEX] - 1 for hap in hass.data[DOMAIN].values(): if entity_id_list != "all": for entity_id in entity_id_list: group = hap.hmip_device_by_entity_id.get(entity_id) if group: await group.set_active_profile(climate_profile_index) else: for group in hap.home.groups: if isinstance(group, AsyncHeatingGroup): await group.set_active_profile(climate_profile_index) hass.services.async_register( DOMAIN, SERVICE_SET_ACTIVE_CLIMATE_PROFILE, _set_active_climate_profile, schema=SCHEMA_SET_ACTIVE_CLIMATE_PROFILE, ) async def _async_dump_hap_config(service): """Service to dump the configuration of a Homematic IP Access Point.""" config_path = (service.data.get(ATTR_CONFIG_OUTPUT_PATH) or hass.config.config_dir) config_file_prefix = service.data[ATTR_CONFIG_OUTPUT_FILE_PREFIX] anonymize = service.data[ATTR_ANONYMIZE] for hap in hass.data[DOMAIN].values(): hap_sgtin = hap.config_entry.title if anonymize: hap_sgtin = hap_sgtin[-4:] file_name = f"{config_file_prefix}_{hap_sgtin}.json" path = Path(config_path) config_file = path / file_name json_state = await hap.home.download_configuration() json_state = handle_config(json_state, anonymize) config_file.write_text(json_state, encoding="utf8") hass.services.async_register( DOMAIN, SERVICE_DUMP_HAP_CONFIG, _async_dump_hap_config, schema=SCHEMA_DUMP_HAP_CONFIG, ) def _get_home(hapid: str): """Return a HmIP home.""" hap = hass.data[DOMAIN].get(hapid) if hap: return hap.home _LOGGER.info("No matching access point found for access point id %s", hapid) return None return True
def async_setup_platform(hass: HomeAssistantType, config: ConfigType, async_add_devices, discovery_info=None): """Set up the cast platform.""" import pychromecast # Import CEC IGNORE attributes pychromecast.IGNORE_CEC += config.get(CONF_IGNORE_CEC, []) hass.data.setdefault(ADDED_CAST_DEVICES_KEY, {}) hass.data.setdefault(KNOWN_CHROMECASTS_KEY, {}) # None -> use discovery; (host, port) -> manually specify chromecast. want_host = None if discovery_info: want_host = (discovery_info.get('host'), discovery_info.get('port')) elif CONF_HOST in config: want_host = (config.get(CONF_HOST), DEFAULT_PORT) enable_discovery = False if want_host is None: # We were explicitly told to enable pychromecast discovery. enable_discovery = True elif want_host[1] != DEFAULT_PORT: # We're trying to add a group, so we have to use pychromecast's # discovery to get the correct friendly name. enable_discovery = True if enable_discovery: @callback def async_cast_discovered(chromecast): """Callback for when a new chromecast is discovered.""" if want_host is not None and \ (chromecast.host, chromecast.port) != want_host: return # for groups, only add requested device cast_device = _async_create_cast_device(hass, chromecast) if cast_device is not None: async_add_devices([cast_device]) async_dispatcher_connect(hass, SIGNAL_CAST_DISCOVERED, async_cast_discovered) # Re-play the callback for all past chromecasts, store the objects in # a list to avoid concurrent modification resulting in exception. for chromecast in list(hass.data[KNOWN_CHROMECASTS_KEY].values()): async_cast_discovered(chromecast) hass.async_add_job(_setup_internal_discovery, hass) else: # Manually add a "normal" Chromecast, we can do that without discovery. try: chromecast = yield from hass.async_add_job(pychromecast.Chromecast, *want_host) except pychromecast.ChromecastConnectionError: _LOGGER.warning("Can't set up chromecast on %s", want_host[0]) raise key = (chromecast.host, chromecast.port, chromecast.uuid) cast_device = _async_create_cast_device(hass, chromecast) if cast_device is not None: hass.data[KNOWN_CHROMECASTS_KEY][key] = chromecast async_add_devices([cast_device])
def _create_weather(knx_module: XKNX, config: ConfigType) -> XknxWeather: """Return a KNX weather device to be used within XKNX.""" return XknxWeather( knx_module, name=config[CONF_NAME], sync_state=config[WeatherSchema.CONF_SYNC_STATE], create_sensors=config[WeatherSchema.CONF_KNX_CREATE_SENSORS], group_address_temperature=config[ WeatherSchema.CONF_KNX_TEMPERATURE_ADDRESS], group_address_brightness_south=config.get( WeatherSchema.CONF_KNX_BRIGHTNESS_SOUTH_ADDRESS), group_address_brightness_east=config.get( WeatherSchema.CONF_KNX_BRIGHTNESS_EAST_ADDRESS), group_address_brightness_west=config.get( WeatherSchema.CONF_KNX_BRIGHTNESS_WEST_ADDRESS), group_address_brightness_north=config.get( WeatherSchema.CONF_KNX_BRIGHTNESS_NORTH_ADDRESS), group_address_wind_speed=config.get( WeatherSchema.CONF_KNX_WIND_SPEED_ADDRESS), group_address_wind_bearing=config.get( WeatherSchema.CONF_KNX_WIND_BEARING_ADDRESS), group_address_rain_alarm=config.get( WeatherSchema.CONF_KNX_RAIN_ALARM_ADDRESS), group_address_frost_alarm=config.get( WeatherSchema.CONF_KNX_FROST_ALARM_ADDRESS), group_address_wind_alarm=config.get( WeatherSchema.CONF_KNX_WIND_ALARM_ADDRESS), group_address_day_night=config.get( WeatherSchema.CONF_KNX_DAY_NIGHT_ADDRESS), group_address_air_pressure=config.get( WeatherSchema.CONF_KNX_AIR_PRESSURE_ADDRESS), group_address_humidity=config.get( WeatherSchema.CONF_KNX_HUMIDITY_ADDRESS), )