Enable config flow for Luftdaten (#17700)

* Move file to new location

* Update requirement

* Enable config flow

* Add luftdaten

* Add tests

* Update

* Add constants

* Changes according to the review comments

* Remove wrong entry from flows

* Fix dict handling

* Add callback and use OrderedDict

* Remve leftover

* Fix

* Remove await
This commit is contained in:
Fabian Affolter 2018-11-06 14:27:52 +01:00 committed by GitHub
parent 7933bd7f91
commit 2e517ab6bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 508 additions and 108 deletions

View file

@ -109,7 +109,6 @@ homeassistant/components/sensor/gpsd.py @fabaff
homeassistant/components/sensor/irish_rail_transport.py @ttroy50
homeassistant/components/sensor/jewish_calendar.py @tsvi
homeassistant/components/sensor/linux_battery.py @fabaff
homeassistant/components/sensor/luftdaten.py @fabaff
homeassistant/components/sensor/miflora.py @danielhiversen @ChristianKuehnel
homeassistant/components/sensor/min_max.py @fabaff
homeassistant/components/sensor/moon.py @fabaff
@ -189,6 +188,8 @@ homeassistant/components/*/konnected.py @heythisisnate
# L
homeassistant/components/lifx.py @amelchio
homeassistant/components/*/lifx.py @amelchio
homeassistant/components/luftdaten/* @fabaff
homeassistant/components/*/luftdaten.py @fabaff
# M
homeassistant/components/matrix.py @tinloaf

View file

@ -0,0 +1,170 @@
"""
Support for Luftdaten stations.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/luftdaten/
"""
import logging
import voluptuous as vol
from homeassistant.config_entries import SOURCE_IMPORT
from homeassistant.const import (
CONF_MONITORED_CONDITIONS, CONF_SCAN_INTERVAL, CONF_SENSORS,
CONF_SHOW_ON_MAP, TEMP_CELSIUS)
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_track_time_interval
from .config_flow import configured_sensors
from .const import CONF_SENSOR_ID, DEFAULT_SCAN_INTERVAL, DOMAIN
REQUIREMENTS = ['luftdaten==0.3.4']
_LOGGER = logging.getLogger(__name__)
DATA_LUFTDATEN = 'luftdaten'
DATA_LUFTDATEN_CLIENT = 'data_luftdaten_client'
DATA_LUFTDATEN_LISTENER = 'data_luftdaten_listener'
DEFAULT_ATTRIBUTION = "Data provided by luftdaten.info"
SENSOR_HUMIDITY = 'humidity'
SENSOR_PM10 = 'P1'
SENSOR_PM2_5 = 'P2'
SENSOR_PRESSURE = 'pressure'
SENSOR_TEMPERATURE = 'temperature'
TOPIC_UPDATE = '{0}_data_update'.format(DOMAIN)
VOLUME_MICROGRAMS_PER_CUBIC_METER = 'µg/m3'
SENSORS = {
SENSOR_TEMPERATURE: ['Temperature', 'mdi:thermometer', TEMP_CELSIUS],
SENSOR_HUMIDITY: ['Humidity', 'mdi:water-percent', '%'],
SENSOR_PRESSURE: ['Pressure', 'mdi:arrow-down-bold', 'Pa'],
SENSOR_PM10: ['PM10', 'mdi:thought-bubble',
VOLUME_MICROGRAMS_PER_CUBIC_METER],
SENSOR_PM2_5: ['PM2.5', 'mdi:thought-bubble-outline',
VOLUME_MICROGRAMS_PER_CUBIC_METER]
}
SENSOR_SCHEMA = vol.Schema({
vol.Optional(CONF_MONITORED_CONDITIONS, default=list(SENSORS)):
vol.All(cv.ensure_list, [vol.In(SENSORS)])
})
CONFIG_SCHEMA = vol.Schema({
DOMAIN:
vol.Schema({
vol.Required(CONF_SENSOR_ID): cv.positive_int,
vol.Optional(CONF_SENSORS, default={}): SENSOR_SCHEMA,
vol.Optional(CONF_SHOW_ON_MAP, default=False): cv.boolean,
vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL):
cv.time_period,
})
}, extra=vol.ALLOW_EXTRA)
async def async_setup(hass, config):
"""Set up the Luftdaten component."""
hass.data[DOMAIN] = {}
hass.data[DOMAIN][DATA_LUFTDATEN_CLIENT] = {}
hass.data[DOMAIN][DATA_LUFTDATEN_LISTENER] = {}
if DOMAIN not in config:
return True
conf = config[DOMAIN]
station_id = conf.get(CONF_SENSOR_ID)
if station_id not in configured_sensors(hass):
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={'source': SOURCE_IMPORT},
data={
CONF_SENSORS: conf[CONF_SENSORS],
CONF_SENSOR_ID: conf[CONF_SENSOR_ID],
CONF_SHOW_ON_MAP: conf[CONF_SHOW_ON_MAP],
}
)
)
hass.data[DOMAIN][CONF_SCAN_INTERVAL] = conf[CONF_SCAN_INTERVAL]
return True
async def async_setup_entry(hass, config_entry):
"""Set up Luftdaten as config entry."""
from luftdaten import Luftdaten
from luftdaten.exceptions import LuftdatenError
session = async_get_clientsession(hass)
try:
luftdaten = LuftDatenData(
Luftdaten(
config_entry.data[CONF_SENSOR_ID], hass.loop, session),
config_entry.data.get(CONF_SENSORS, {}).get(
CONF_MONITORED_CONDITIONS, list(SENSORS)))
await luftdaten.async_update()
hass.data[DOMAIN][DATA_LUFTDATEN_CLIENT][config_entry.entry_id] = \
luftdaten
except LuftdatenError:
raise ConfigEntryNotReady
hass.async_create_task(hass.config_entries.async_forward_entry_setup(
config_entry, 'sensor'))
async def refresh_sensors(event_time):
"""Refresh Luftdaten data."""
await luftdaten.async_update()
async_dispatcher_send(hass, TOPIC_UPDATE)
hass.data[DOMAIN][DATA_LUFTDATEN_LISTENER][
config_entry.entry_id] = async_track_time_interval(
hass, refresh_sensors,
hass.data[DOMAIN].get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL))
return True
async def async_unload_entry(hass, config_entry):
"""Unload an Luftdaten config entry."""
remove_listener = hass.data[DOMAIN][DATA_LUFTDATEN_LISTENER].pop(
config_entry.entry_id)
remove_listener()
for component in ('sensor', ):
await hass.config_entries.async_forward_entry_unload(
config_entry, component)
hass.data[DOMAIN][DATA_LUFTDATEN_CLIENT].pop(config_entry.entry_id)
return True
class LuftDatenData:
"""Define a generic Luftdaten object."""
def __init__(self, client, sensor_conditions):
"""Initialize the Luftdata object."""
self.client = client
self.data = {}
self.sensor_conditions = sensor_conditions
async def async_update(self):
"""Update sensor/binary sensor data."""
from luftdaten.exceptions import LuftdatenError
try:
await self.client.get_data()
self.data[DATA_LUFTDATEN] = self.client.values
self.data[DATA_LUFTDATEN].update(self.client.meta)
except LuftdatenError:
_LOGGER.error("Unable to retrieve data from luftdaten.info")

View file

@ -0,0 +1,75 @@
"""Config flow to configure the Luftdaten component."""
from collections import OrderedDict
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_SCAN_INTERVAL, CONF_SHOW_ON_MAP
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client
from .const import CONF_SENSOR_ID, DEFAULT_SCAN_INTERVAL, DOMAIN
@callback
def configured_sensors(hass):
"""Return a set of configured Luftdaten sensors."""
return set(
'{0}'.format(entry.data[CONF_SENSOR_ID])
for entry in hass.config_entries.async_entries(DOMAIN))
@config_entries.HANDLERS.register(DOMAIN)
class LuftDatenFlowHandler(config_entries.ConfigFlow):
"""Handle a Luftdaten config flow."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
@callback
def _show_form(self, errors=None):
"""Show the form to the user."""
data_schema = OrderedDict()
data_schema[vol.Required(CONF_SENSOR_ID)] = str
data_schema[vol.Optional(CONF_SHOW_ON_MAP, default=False)] = bool
return self.async_show_form(
step_id='user',
data_schema=vol.Schema(data_schema),
errors=errors or {}
)
async def async_step_import(self, import_config):
"""Import a config entry from configuration.yaml."""
return await self.async_step_user(import_config)
async def async_step_user(self, user_input=None):
"""Handle the start of the config flow."""
from luftdaten import Luftdaten, exceptions
if not user_input:
return self._show_form()
sensor_id = user_input[CONF_SENSOR_ID]
if sensor_id in configured_sensors(self.hass):
return self._show_form({CONF_SENSOR_ID: 'sensor_exists'})
session = aiohttp_client.async_get_clientsession(self.hass)
luftdaten = Luftdaten(
user_input[CONF_SENSOR_ID], self.hass.loop, session)
try:
await luftdaten.get_data()
valid = await luftdaten.validate_sensor()
except exceptions.LuftdatenConnectionError:
return self._show_form(
{CONF_SENSOR_ID: 'communication_error'})
if not valid:
return self._show_form({CONF_SENSOR_ID: 'invalid_sensor'})
scan_interval = user_input.get(
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
user_input.update({CONF_SCAN_INTERVAL: scan_interval.seconds})
return self.async_create_entry(title=sensor_id, data=user_input)

View file

@ -0,0 +1,10 @@
"""Define constants for the Luftdaten component."""
from datetime import timedelta
ATTR_SENSOR_ID = 'sensor_id'
CONF_SENSOR_ID = 'sensor_id'
DEFAULT_SCAN_INTERVAL = timedelta(minutes=10)
DOMAIN = 'luftdaten'

View file

@ -0,0 +1,20 @@
{
"config": {
"title": "Luftdaten",
"step": {
"user": {
"title": "Define Luftdaten",
"data": {
"station_id": "Luftdaten Sensor ID",
"show_on_map": "Show on map"
}
}
},
"error": {
"sensor_exists": "Sensor already registered",
"invalid_sensor": "Sensor not available or invalid",
"communication_error": "Unable to communicate with the Luftdaten API"
}
}
}

View file

@ -4,152 +4,120 @@ Support for Luftdaten sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.luftdaten/
"""
from datetime import timedelta
import logging
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.components.luftdaten import (
DATA_LUFTDATEN, DATA_LUFTDATEN_CLIENT, DEFAULT_ATTRIBUTION, DOMAIN,
SENSORS, TOPIC_UPDATE)
from homeassistant.components.luftdaten.const import ATTR_SENSOR_ID
from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_LATITUDE, ATTR_LONGITUDE, CONF_MONITORED_CONDITIONS,
CONF_NAME, CONF_SHOW_ON_MAP, TEMP_CELSIUS)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
ATTR_ATTRIBUTION, ATTR_LATITUDE, ATTR_LONGITUDE, CONF_SHOW_ON_MAP)
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
REQUIREMENTS = ['luftdaten==0.2.0']
_LOGGER = logging.getLogger(__name__)
ATTR_SENSOR_ID = 'sensor_id'
CONF_ATTRIBUTION = "Data provided by luftdaten.info"
VOLUME_MICROGRAMS_PER_CUBIC_METER = 'µg/m3'
SENSOR_TEMPERATURE = 'temperature'
SENSOR_HUMIDITY = 'humidity'
SENSOR_PM10 = 'P1'
SENSOR_PM2_5 = 'P2'
SENSOR_PRESSURE = 'pressure'
SENSOR_TYPES = {
SENSOR_TEMPERATURE: ['Temperature', TEMP_CELSIUS],
SENSOR_HUMIDITY: ['Humidity', '%'],
SENSOR_PRESSURE: ['Pressure', 'Pa'],
SENSOR_PM10: ['PM10', VOLUME_MICROGRAMS_PER_CUBIC_METER],
SENSOR_PM2_5: ['PM2.5', VOLUME_MICROGRAMS_PER_CUBIC_METER]
}
DEFAULT_NAME = 'Luftdaten'
CONF_SENSORID = 'sensorid'
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=5)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SENSORID): cv.positive_int,
vol.Required(CONF_MONITORED_CONDITIONS):
vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_SHOW_ON_MAP, default=False): cv.boolean,
})
DEPENDENCIES = ['luftdaten']
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
"""Set up the Luftdaten sensor."""
from luftdaten import Luftdaten
"""Set up an Luftdaten sensor based on existing config."""
pass
name = config.get(CONF_NAME)
show_on_map = config.get(CONF_SHOW_ON_MAP)
sensor_id = config.get(CONF_SENSORID)
session = async_get_clientsession(hass)
luftdaten = LuftdatenData(Luftdaten(sensor_id, hass.loop, session))
async def async_setup_entry(hass, entry, async_add_entities):
"""Set up a Luftdaten sensor based on a config entry."""
luftdaten = hass.data[DOMAIN][DATA_LUFTDATEN_CLIENT][entry.entry_id]
await luftdaten.async_update()
sensors = []
for sensor_type in luftdaten.sensor_conditions:
name, icon, unit = SENSORS[sensor_type]
sensors.append(
LuftdatenSensor(
luftdaten, sensor_type, name, icon, unit,
entry.data[CONF_SHOW_ON_MAP])
)
if luftdaten.data is None:
_LOGGER.error("Sensor is not available: %s", sensor_id)
return
devices = []
for variable in config[CONF_MONITORED_CONDITIONS]:
if luftdaten.data.values[variable] is None:
_LOGGER.warning("It might be that sensor %s is not providing "
"measurements for %s", sensor_id, variable)
devices.append(
LuftdatenSensor(luftdaten, name, variable, sensor_id, show_on_map))
async_add_entities(devices)
async_add_entities(sensors, True)
class LuftdatenSensor(Entity):
"""Implementation of a Luftdaten sensor."""
def __init__(self, luftdaten, name, sensor_type, sensor_id, show):
def __init__(
self, luftdaten, sensor_type, name, icon, unit, show):
"""Initialize the Luftdaten sensor."""
self._async_unsub_dispatcher_connect = None
self.luftdaten = luftdaten
self._icon = icon
self._name = name
self._state = None
self._sensor_id = sensor_id
self._data = None
self.sensor_type = sensor_type
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
self._unit_of_measurement = unit
self._show_on_map = show
self._attrs = {}
@property
def name(self):
"""Return the name of the sensor."""
return '{} {}'.format(self._name, SENSOR_TYPES[self.sensor_type][0])
def icon(self):
"""Return the icon."""
return self._icon
@property
def state(self):
"""Return the state of the device."""
return self.luftdaten.data.values[self.sensor_type]
return self._data[self.sensor_type]
@property
def unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
return self._unit_of_measurement
@property
def should_poll(self):
"""Disable polling."""
return False
@property
def unique_id(self) -> str:
"""Return a unique, friendly identifier for this entity."""
return '{0}_{1}'.format(self._data['sensor_id'], self.sensor_type)
@property
def device_state_attributes(self):
"""Return the state attributes."""
onmap = ATTR_LATITUDE, ATTR_LONGITUDE
nomap = 'lat', 'long'
lat_format, lon_format = onmap if self._show_on_map else nomap
self._attrs[ATTR_SENSOR_ID] = self._data['sensor_id']
self._attrs[ATTR_ATTRIBUTION] = DEFAULT_ATTRIBUTION
on_map = ATTR_LATITUDE, ATTR_LONGITUDE
no_map = 'lat', 'long'
lat_format, lon_format = on_map if self._show_on_map else no_map
try:
attr = {
ATTR_ATTRIBUTION: CONF_ATTRIBUTION,
ATTR_SENSOR_ID: self._sensor_id,
lat_format: self.luftdaten.data.meta['latitude'],
lon_format: self.luftdaten.data.meta['longitude'],
}
return attr
self._attrs[lon_format] = self._data['longitude']
self._attrs[lat_format] = self._data['latitude']
return self._attrs
except KeyError:
return
async def async_added_to_hass(self):
"""Register callbacks."""
@callback
def update():
"""Update the state."""
self.async_schedule_update_ha_state(True)
self._async_unsub_dispatcher_connect = async_dispatcher_connect(
self.hass, TOPIC_UPDATE, update)
async def async_will_remove_from_hass(self):
"""Disconnect dispatcher listener when removed."""
if self._async_unsub_dispatcher_connect:
self._async_unsub_dispatcher_connect()
async def async_update(self):
"""Get the latest data from luftdaten.info and update the state."""
await self.luftdaten.async_update()
class LuftdatenData:
"""Class for handling the data retrieval."""
def __init__(self, data):
"""Initialize the data object."""
self.data = data
@Throttle(MIN_TIME_BETWEEN_UPDATES)
async def async_update(self):
"""Get the latest data from luftdaten.info."""
from luftdaten.exceptions import LuftdatenError
"""Get the latest data and update the state."""
try:
await self.data.async_get_data()
except LuftdatenError:
_LOGGER.error("Unable to retrieve data from luftdaten.info")
self._data = self.luftdaten.data[DATA_LUFTDATEN]
except KeyError:
return

View file

@ -145,6 +145,7 @@ FLOWS = [
'ios',
'lifx',
'mailgun',
'luftdaten',
'mqtt',
'nest',
'openuv',

View file

@ -590,8 +590,8 @@ locationsharinglib==3.0.7
# homeassistant.components.logi_circle
logi_circle==0.1.7
# homeassistant.components.sensor.luftdaten
luftdaten==0.2.0
# homeassistant.components.luftdaten
luftdaten==0.3.4
# homeassistant.components.light.lw12wifi
lw12==0.9.2

View file

@ -112,6 +112,9 @@ libpurecoollink==0.4.2
# homeassistant.components.media_player.soundtouch
libsoundtouch==0.7.2
# homeassistant.components.luftdaten
luftdaten==0.3.4
# homeassistant.components.sensor.mfi
# homeassistant.components.switch.mfi
mficlient==0.3.0

View file

@ -50,12 +50,12 @@ TEST_REQUIREMENTS = (
'evohomeclient',
'feedparser',
'foobot_async',
'gTTS-token',
'geojson_client',
'georss_client',
'gTTS-token',
'ha-ffmpeg',
'hangups',
'HAP-python',
'ha-ffmpeg',
'haversine',
'hbmqtt',
'hdate',
@ -65,6 +65,7 @@ TEST_REQUIREMENTS = (
'influxdb',
'libpurecoollink',
'libsoundtouch',
'luftdaten',
'mficlient',
'numpy',
'paho-mqtt',

View file

@ -0,0 +1 @@
"""Define tests for the Luftdaten component."""

View file

@ -0,0 +1,114 @@
"""Define tests for the Luftdaten config flow."""
from datetime import timedelta
from unittest.mock import patch
from homeassistant import data_entry_flow
from homeassistant.components.luftdaten import DOMAIN, config_flow
from homeassistant.components.luftdaten.const import CONF_SENSOR_ID
from homeassistant.const import CONF_SCAN_INTERVAL, CONF_SHOW_ON_MAP
from tests.common import MockConfigEntry, mock_coro
async def test_duplicate_error(hass):
"""Test that errors are shown when duplicates are added."""
conf = {
CONF_SENSOR_ID: '12345abcde',
}
MockConfigEntry(domain=DOMAIN, data=conf).add_to_hass(hass)
flow = config_flow.LuftDatenFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=conf)
assert result['errors'] == {CONF_SENSOR_ID: 'sensor_exists'}
async def test_communication_error(hass):
"""Test that no sensor is added while unable to communicate with API."""
conf = {
CONF_SENSOR_ID: '12345abcde',
}
flow = config_flow.LuftDatenFlowHandler()
flow.hass = hass
with patch('luftdaten.Luftdaten.get_data', return_value=mock_coro(None)):
result = await flow.async_step_user(user_input=conf)
assert result['errors'] == {CONF_SENSOR_ID: 'invalid_sensor'}
async def test_invalid_sensor(hass):
"""Test that an invalid sensor throws an error."""
conf = {
CONF_SENSOR_ID: '12345abcde',
}
flow = config_flow.LuftDatenFlowHandler()
flow.hass = hass
with patch('luftdaten.Luftdaten.get_data', return_value=mock_coro(False)),\
patch('luftdaten.Luftdaten.validate_sensor',
return_value=mock_coro(False)):
result = await flow.async_step_user(user_input=conf)
assert result['errors'] == {CONF_SENSOR_ID: 'invalid_sensor'}
async def test_show_form(hass):
"""Test that the form is served with no input."""
flow = config_flow.LuftDatenFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=None)
assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
assert result['step_id'] == 'user'
async def test_step_import(hass):
"""Test that the import step works."""
conf = {
CONF_SENSOR_ID: '12345abcde',
CONF_SHOW_ON_MAP: False,
}
flow = config_flow.LuftDatenFlowHandler()
flow.hass = hass
with patch('luftdaten.Luftdaten.get_data', return_value=mock_coro(True)), \
patch('luftdaten.Luftdaten.validate_sensor',
return_value=mock_coro(True)):
result = await flow.async_step_import(import_config=conf)
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result['title'] == '12345abcde'
assert result['data'] == {
CONF_SENSOR_ID: '12345abcde',
CONF_SHOW_ON_MAP: False,
CONF_SCAN_INTERVAL: 600,
}
async def test_step_user(hass):
"""Test that the user step works."""
conf = {
CONF_SENSOR_ID: '12345abcde',
CONF_SHOW_ON_MAP: False,
CONF_SCAN_INTERVAL: timedelta(minutes=5),
}
flow = config_flow.LuftDatenFlowHandler()
flow.hass = hass
with patch('luftdaten.Luftdaten.get_data', return_value=mock_coro(True)), \
patch('luftdaten.Luftdaten.validate_sensor',
return_value=mock_coro(True)):
result = await flow.async_step_user(user_input=conf)
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result['title'] == '12345abcde'
assert result['data'] == {
CONF_SENSOR_ID: '12345abcde',
CONF_SHOW_ON_MAP: False,
CONF_SCAN_INTERVAL: 300,
}

View file

@ -0,0 +1,36 @@
"""Test the Luftdaten component setup."""
from unittest.mock import patch
from homeassistant.components import luftdaten
from homeassistant.components.luftdaten.const import CONF_SENSOR_ID, DOMAIN
from homeassistant.const import CONF_SCAN_INTERVAL, CONF_SHOW_ON_MAP
from homeassistant.setup import async_setup_component
async def test_config_with_sensor_passed_to_config_entry(hass):
"""Test that configured options for a sensor are loaded."""
conf = {
CONF_SENSOR_ID: '12345abcde',
CONF_SHOW_ON_MAP: False,
CONF_SCAN_INTERVAL: 600,
}
with patch.object(hass, 'config_entries') as mock_config_entries, \
patch.object(luftdaten, 'configured_sensors', return_value=[]):
assert await async_setup_component(hass, DOMAIN, conf) is True
assert len(mock_config_entries.flow.mock_calls) == 0
async def test_config_already_registered_not_passed_to_config_entry(hass):
"""Test that an already registered sensor does not initiate an import."""
conf = {
CONF_SENSOR_ID: '12345abcde',
}
with patch.object(hass, 'config_entries') as mock_config_entries, \
patch.object(luftdaten, 'configured_sensors',
return_value=['12345abcde']):
assert await async_setup_component(hass, DOMAIN, conf) is True
assert len(mock_config_entries.flow.mock_calls) == 0