async def async_step_node_pro(self, user_input=None): """Handle the initialization of the integration with a Node/Pro.""" if not user_input: return self.async_show_form(step_id="node_pro", data_schema=self.node_pro_schema) await self._async_set_unique_id(user_input[CONF_IP_ADDRESS]) websession = aiohttp_client.async_get_clientsession(self.hass) client = Client(websession) try: await client.node.from_samba(user_input[CONF_IP_ADDRESS], user_input[CONF_PASSWORD]) except NodeProError as err: LOGGER.error("Error connecting to Node/Pro unit: %s", err) return self.async_show_form( step_id="node_pro", data_schema=self.node_pro_schema, errors={CONF_IP_ADDRESS: "unable_to_connect"}, ) return self.async_create_entry( title=f"Node/Pro ({user_input[CONF_IP_ADDRESS]})", data={ **user_input, CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_NODE_PRO }, )
async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" if not user_input: return await self._show_form() geo_id = async_get_geography_id(user_input) await self._async_set_unique_id(geo_id) websession = aiohttp_client.async_get_clientsession(self.hass) client = Client(websession, api_key=user_input[CONF_API_KEY]) # If this is the first (and only the first) time we've seen this API key, check # that it's valid: checked_keys = self.hass.data.setdefault("airvisual_checked_api_keys", set()) check_keys_lock = self.hass.data.setdefault( "airvisual_checked_api_keys_lock", asyncio.Lock()) async with check_keys_lock: if user_input[CONF_API_KEY] not in checked_keys: try: await client.api.nearest_city() except InvalidKeyError: return await self._show_form( errors={CONF_API_KEY: "invalid_api_key"}) checked_keys.add(user_input[CONF_API_KEY]) return self.async_create_entry(title=f"Cloud API ({geo_id})", data=user_input)
async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): """Configure the platform and add the sensors.""" from pyairvisual import Client city = config.get(CONF_CITY) state = config.get(CONF_STATE) country = config.get(CONF_COUNTRY) latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) websession = aiohttp_client.async_get_clientsession(hass) if city and state and country: _LOGGER.debug( "Using city, state, and country: %s, %s, %s", city, state, country) location_id = ','.join((city, state, country)) data = AirVisualData( Client(config[CONF_API_KEY], websession), city=city, state=state, country=country, show_on_map=config[CONF_SHOW_ON_MAP], scan_interval=config[CONF_SCAN_INTERVAL]) else: _LOGGER.debug( "Using latitude and longitude: %s, %s", latitude, longitude) location_id = ','.join((str(latitude), str(longitude))) data = AirVisualData( Client(config[CONF_API_KEY], websession), latitude=latitude, longitude=longitude, show_on_map=config[CONF_SHOW_ON_MAP], scan_interval=config[CONF_SCAN_INTERVAL]) await data.async_update() sensors = [] for locale in config[CONF_MONITORED_CONDITIONS]: for kind, name, icon, unit in SENSORS: sensors.append( AirVisualSensor( data, kind, name, icon, unit, locale, location_id)) async_add_entities(sensors, True)
async def async_setup_entry(hass, config_entry): """Set up AirVisual as config entry.""" websession = aiohttp_client.async_get_clientsession(hass) if CONF_API_KEY in config_entry.data: _standardize_geography_config_entry(hass, config_entry) airvisual = AirVisualGeographyData( hass, Client(websession, api_key=config_entry.data[CONF_API_KEY]), config_entry, ) # Only geography-based entries have options: config_entry.add_update_listener(async_update_options) else: _standardize_node_pro_config_entry(hass, config_entry) airvisual = AirVisualNodeProData(hass, Client(websession), config_entry) await airvisual.async_update() hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = airvisual for component in PLATFORMS: hass.async_create_task( hass.config_entries.async_forward_entry_setup( config_entry, component)) async def refresh(event_time): """Refresh data from AirVisual.""" await airvisual.async_update() hass.data[DOMAIN][DATA_LISTENER][ config_entry.entry_id] = async_track_time_interval( hass, refresh, airvisual.scan_interval) return True
async def async_step_geography(self, user_input=None): """Handle the initialization of the integration via the cloud API.""" if not user_input: return self.async_show_form(step_id="geography", data_schema=self.geography_schema) geo_id = async_get_geography_id(user_input) await self._async_set_unique_id(geo_id) self._abort_if_unique_id_configured() # Find older config entries without unique ID: for entry in self._async_current_entries(): if entry.version != 1: continue if any(geo_id == async_get_geography_id(geography) for geography in entry.data[CONF_GEOGRAPHIES]): return self.async_abort(reason="already_configured") websession = aiohttp_client.async_get_clientsession(self.hass) client = Client(session=websession, api_key=user_input[CONF_API_KEY]) # If this is the first (and only the first) time we've seen this API key, check # that it's valid: checked_keys = self.hass.data.setdefault("airvisual_checked_api_keys", set()) check_keys_lock = self.hass.data.setdefault( "airvisual_checked_api_keys_lock", asyncio.Lock()) async with check_keys_lock: if user_input[CONF_API_KEY] not in checked_keys: try: await client.api.nearest_city() except InvalidKeyError: return self.async_show_form( step_id="geography", data_schema=self.geography_schema, errors={CONF_API_KEY: "invalid_api_key"}, ) checked_keys.add(user_input[CONF_API_KEY]) return self.async_create_entry( title=f"Cloud API ({geo_id})", data={ **user_input, CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_GEOGRAPHY }, )
async def async_setup_entry(hass, config_entry): """Set up AirVisual as config entry.""" entry_updates = {} if not config_entry.unique_id: # If the config entry doesn't already have a unique ID, set one: entry_updates["unique_id"] = config_entry.data[CONF_API_KEY] if not config_entry.options: # If the config entry doesn't already have any options set, set defaults: entry_updates["options"] = DEFAULT_OPTIONS if entry_updates: hass.config_entries.async_update_entry(config_entry, **entry_updates) websession = aiohttp_client.async_get_clientsession(hass) hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = AirVisualData( hass, Client(websession, api_key=config_entry.data[CONF_API_KEY]), config_entry) try: await hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id ].async_update() except InvalidKeyError: _LOGGER.error("Invalid API key provided") raise ConfigEntryNotReady hass.async_create_task( hass.config_entries.async_forward_entry_setup(config_entry, "sensor")) async def refresh(event_time): """Refresh data from AirVisual.""" await hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id ].async_update() hass.data[DOMAIN][DATA_LISTENER][ config_entry.entry_id] = async_track_time_interval( hass, refresh, DEFAULT_SCAN_INTERVAL) config_entry.add_update_listener(async_update_options) return True
async def async_setup_entry(hass, config_entry): """Set up AirVisual as config entry.""" websession = aiohttp_client.async_get_clientsession(hass) if CONF_API_KEY in config_entry.data: _standardize_geography_config_entry(hass, config_entry) client = Client(api_key=config_entry.data[CONF_API_KEY], session=websession) update_interval = async_get_cloud_api_update_interval( hass, config_entry.data[CONF_API_KEY]) async def async_update_data(): """Get new data from the API.""" if CONF_CITY in config_entry.data: api_coro = client.api.city( config_entry.data[CONF_CITY], config_entry.data[CONF_STATE], config_entry.data[CONF_COUNTRY], ) else: api_coro = client.api.nearest_city( config_entry.data[CONF_LATITUDE], config_entry.data[CONF_LONGITUDE], ) try: return await api_coro except AirVisualError as err: raise UpdateFailed(f"Error while retrieving data: {err}") coordinator = DataUpdateCoordinator( hass, LOGGER, name="geography data", update_interval=update_interval, update_method=async_update_data, ) # Ensure any other, existing config entries that use this API key are updated # with the new scan interval: async_reset_coordinator_update_intervals(hass, update_interval) # Only geography-based entries have options: config_entry.add_update_listener(async_update_options) else: _standardize_node_pro_config_entry(hass, config_entry) client = Client(session=websession) async def async_update_data(): """Get new data from the API.""" try: return await client.node.from_samba( config_entry.data[CONF_IP_ADDRESS], config_entry.data[CONF_PASSWORD], include_history=False, include_trends=False, ) except NodeProError as err: raise UpdateFailed(f"Error while retrieving data: {err}") coordinator = DataUpdateCoordinator( hass, LOGGER, name="Node/Pro data", update_interval=DEFAULT_NODE_PRO_SCAN_INTERVAL, update_method=async_update_data, ) await coordinator.async_refresh() hass.data[DOMAIN][DATA_COORDINATOR][config_entry.entry_id] = coordinator for component in PLATFORMS: hass.async_create_task( hass.config_entries.async_forward_entry_setup( config_entry, component)) return True
async def async_setup_entry(hass, config_entry): """Set up AirVisual as config entry.""" websession = aiohttp_client.async_get_clientsession(hass) if CONF_API_KEY in config_entry.data: _standardize_geography_config_entry(hass, config_entry) client = Client(api_key=config_entry.data[CONF_API_KEY], session=websession) async def async_update_data(): """Get new data from the API.""" if CONF_CITY in config_entry.data: api_coro = client.api.city( config_entry.data[CONF_CITY], config_entry.data[CONF_STATE], config_entry.data[CONF_COUNTRY], ) else: api_coro = client.api.nearest_city( config_entry.data[CONF_LATITUDE], config_entry.data[CONF_LONGITUDE], ) try: return await api_coro except AirVisualError as err: raise UpdateFailed(f"Error while retrieving data: {err}") coordinator = DataUpdateCoordinator( hass, LOGGER, name=async_get_geography_id(config_entry.data), # We give a placeholder update interval in order to create the coordinator; # then, below, we use the coordinator's presence (along with any other # coordinators using the same API key) to calculate an actual, leveled # update interval: update_interval=timedelta(minutes=5), update_method=async_update_data, ) hass.data[DOMAIN][DATA_COORDINATOR][config_entry.entry_id] = coordinator async_sync_geo_coordinator_update_intervals( hass, config_entry.data[CONF_API_KEY] ) # Only geography-based entries have options: config_entry.add_update_listener(async_update_options) else: _standardize_node_pro_config_entry(hass, config_entry) client = Client(session=websession) async def async_update_data(): """Get new data from the API.""" try: return await client.node.from_samba( config_entry.data[CONF_IP_ADDRESS], config_entry.data[CONF_PASSWORD], include_history=False, include_trends=False, ) except NodeProError as err: raise UpdateFailed(f"Error while retrieving data: {err}") coordinator = DataUpdateCoordinator( hass, LOGGER, name="Node/Pro data", update_interval=DEFAULT_NODE_PRO_UPDATE_INTERVAL, update_method=async_update_data, ) hass.data[DOMAIN][DATA_COORDINATOR][config_entry.entry_id] = coordinator await coordinator.async_refresh() for component in PLATFORMS: hass.async_create_task( hass.config_entries.async_forward_entry_setup(config_entry, component) ) return True