Add config entry for Flu Near You (#32858)

* Add config flow for Flu Near You

* Cleanup

* Cleanup

* Add tests

* Add test requirements

* Code review

* Reduce unnecessary async-ness

* Handle API registration

* Cleanup

* Update homeassistant/components/flunearyou/.translations/en.json

Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io>

* Code review

* Ensure config schema allows additional keys

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
pull/33557/head
Aaron Bach 2020-04-02 17:54:11 -06:00 committed by GitHub
parent 55870aec31
commit cb058ff6c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 521 additions and 125 deletions

View File

@ -219,6 +219,7 @@ omit =
homeassistant/components/flic/binary_sensor.py
homeassistant/components/flock/notify.py
homeassistant/components/flume/*
homeassistant/components/flunearyou/__init__.py
homeassistant/components/flunearyou/sensor.py
homeassistant/components/flux_led/light.py
homeassistant/components/folder/sensor.py

View File

@ -0,0 +1,21 @@
{
"config": {
"abort": {
"already_configured": "These coordinates are already registered."
},
"error": {
"general_error": "There was an unknown error."
},
"step": {
"user": {
"data": {
"latitude": "Latitude",
"longitude": "Longitude"
},
"description": "Monitor user-based and CDC flu reports.",
"title": "Configure Flu Near You"
}
},
"title": "Flu Near You"
}
}

View File

@ -1 +1,216 @@
"""The flunearyou component."""
import asyncio
from datetime import timedelta
from pyflunearyou import Client
from pyflunearyou.errors import FluNearYouError
import voluptuous as vol
from homeassistant.config_entries import SOURCE_IMPORT
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.core import callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import aiohttp_client, config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_track_time_interval
from .const import (
CATEGORY_CDC_REPORT,
CATEGORY_USER_REPORT,
DATA_CLIENT,
DOMAIN,
LOGGER,
SENSORS,
TOPIC_UPDATE,
)
DATA_LISTENER = "listener"
DEFAULT_SCAN_INTERVAL = timedelta(minutes=30)
CONFIG_SCHEMA = vol.Schema(
{
vol.Optional(DOMAIN): vol.Schema(
{
vol.Optional(CONF_LATITUDE): cv.latitude,
vol.Optional(CONF_LONGITUDE): cv.longitude,
}
)
},
extra=vol.ALLOW_EXTRA,
)
@callback
def async_get_api_category(sensor_type):
"""Get the category that a particular sensor type belongs to."""
try:
return next(
(
category
for category, sensors in SENSORS.items()
for sensor in sensors
if sensor[0] == sensor_type
)
)
except StopIteration:
raise ValueError(f"Can't find category sensor type: {sensor_type}")
async def async_setup(hass, config):
"""Set up the Flu Near You component."""
hass.data[DOMAIN] = {DATA_CLIENT: {}, DATA_LISTENER: {}}
if DOMAIN not in config:
return True
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={
CONF_LATITUDE: config[DOMAIN].get(CONF_LATITUDE, hass.config.latitude),
CONF_LONGITUDE: config[DOMAIN].get(
CONF_LATITUDE, hass.config.longitude
),
},
)
)
return True
async def async_setup_entry(hass, config_entry):
"""Set up Flu Near You as config entry."""
websession = aiohttp_client.async_get_clientsession(hass)
fny = FluNearYouData(
hass,
Client(websession),
config_entry.data.get(CONF_LATITUDE, hass.config.latitude),
config_entry.data.get(CONF_LONGITUDE, hass.config.longitude),
)
try:
await fny.async_update()
except FluNearYouError as err:
LOGGER.error("Error while setting up integration: %s", err)
raise ConfigEntryNotReady
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = fny
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, "sensor")
)
async def refresh(event_time):
"""Refresh data from Flu Near You."""
await fny.async_update()
hass.data[DOMAIN][DATA_LISTENER][config_entry.entry_id] = async_track_time_interval(
hass, refresh, DEFAULT_SCAN_INTERVAL
)
return True
async def async_unload_entry(hass, config_entry):
"""Unload an Flu Near You config entry."""
hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id)
remove_listener = hass.data[DOMAIN][DATA_LISTENER].pop(config_entry.entry_id)
remove_listener()
await hass.config_entries.async_forward_entry_unload(config_entry, "sensor")
return True
class FluNearYouData:
"""Define a data object to retrieve info from Flu Near You."""
def __init__(self, hass, client, latitude, longitude):
"""Initialize."""
self._async_cancel_time_interval_listener = None
self._client = client
self._hass = hass
self.data = {}
self.latitude = latitude
self.longitude = longitude
self._api_coros = {
CATEGORY_CDC_REPORT: self._client.cdc_reports.status_by_coordinates(
latitude, longitude
),
CATEGORY_USER_REPORT: self._client.user_reports.status_by_coordinates(
latitude, longitude
),
}
self._api_category_count = {
CATEGORY_CDC_REPORT: 0,
CATEGORY_USER_REPORT: 0,
}
self._api_category_locks = {
CATEGORY_CDC_REPORT: asyncio.Lock(),
CATEGORY_USER_REPORT: asyncio.Lock(),
}
async def _async_get_data_from_api(self, api_category):
"""Update and save data for a particular API category."""
if self._api_category_count[api_category] == 0:
return
try:
self.data[api_category] = await self._api_coros[api_category]
except FluNearYouError as err:
LOGGER.error("Unable to get %s data: %s", api_category, err)
self.data[api_category] = None
async def _async_update_listener_action(self, now):
"""Define an async_track_time_interval action to update data."""
await self.async_update()
@callback
def async_deregister_api_interest(self, sensor_type):
"""Decrement the number of entities with data needs from an API category."""
# If this deregistration should leave us with no registration at all, remove the
# time interval:
if sum(self._api_category_count.values()) == 0:
if self._async_cancel_time_interval_listener:
self._async_cancel_time_interval_listener()
self._async_cancel_time_interval_listener = None
return
api_category = async_get_api_category(sensor_type)
self._api_category_count[api_category] -= 1
async def async_register_api_interest(self, sensor_type):
"""Increment the number of entities with data needs from an API category."""
# If this is the first registration we have, start a time interval:
if not self._async_cancel_time_interval_listener:
self._async_cancel_time_interval_listener = async_track_time_interval(
self._hass, self._async_update_listener_action, DEFAULT_SCAN_INTERVAL,
)
api_category = async_get_api_category(sensor_type)
self._api_category_count[api_category] += 1
# If a sensor registers interest in a particular API call and the data doesn't
# exist for it yet, make the API call and grab the data:
async with self._api_category_locks[api_category]:
if api_category not in self.data:
await self._async_get_data_from_api(api_category)
async def async_update(self):
"""Update Flu Near You data."""
tasks = [
self._async_get_data_from_api(api_category)
for api_category in self._api_coros
]
await asyncio.gather(*tasks)
LOGGER.debug("Received new data")
async_dispatcher_send(self._hass, TOPIC_UPDATE)

View File

@ -0,0 +1,60 @@
"""Define a config flow manager for flunearyou."""
from pyflunearyou import Client
from pyflunearyou.errors import FluNearYouError
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.helpers import aiohttp_client, config_validation as cv
from .const import DOMAIN, LOGGER # pylint: disable=unused-import
class FluNearYouFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle an FluNearYou config flow."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
@property
def data_schema(self):
"""Return the data schema for integration."""
return vol.Schema(
{
vol.Required(
CONF_LATITUDE, default=self.hass.config.latitude
): cv.latitude,
vol.Required(
CONF_LONGITUDE, default=self.hass.config.longitude
): cv.longitude,
}
)
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."""
if not user_input:
return self.async_show_form(step_id="user", data_schema=self.data_schema)
unique_id = f"{user_input[CONF_LATITUDE]}, {user_input[CONF_LONGITUDE]}"
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()
websession = aiohttp_client.async_get_clientsession(self.hass)
client = Client(websession)
try:
await client.cdc_reports.status_by_coordinates(
user_input[CONF_LATITUDE], user_input[CONF_LONGITUDE]
)
except FluNearYouError as err:
LOGGER.error("Error while setting up integration: %s", err)
return self.async_show_form(
step_id="user", errors={"base": "general_error"}
)
return self.async_create_entry(title=unique_id, data=user_input)

View File

@ -0,0 +1,38 @@
"""Define flunearyou constants."""
import logging
DOMAIN = "flunearyou"
LOGGER = logging.getLogger("homeassistant.components.flunearyou")
DATA_CLIENT = "client"
CATEGORY_CDC_REPORT = "cdc_report"
CATEGORY_USER_REPORT = "user_report"
TOPIC_UPDATE = "flunearyou_update"
TYPE_CDC_LEVEL = "level"
TYPE_CDC_LEVEL2 = "level2"
TYPE_USER_CHICK = "chick"
TYPE_USER_DENGUE = "dengue"
TYPE_USER_FLU = "flu"
TYPE_USER_LEPTO = "lepto"
TYPE_USER_NO_SYMPTOMS = "none"
TYPE_USER_SYMPTOMS = "symptoms"
TYPE_USER_TOTAL = "total"
SENSORS = {
CATEGORY_CDC_REPORT: [
(TYPE_CDC_LEVEL, "CDC Level", "mdi:biohazard", None),
(TYPE_CDC_LEVEL2, "CDC Level 2", "mdi:biohazard", None),
],
CATEGORY_USER_REPORT: [
(TYPE_USER_CHICK, "Avian Flu Symptoms", "mdi:alert", "reports"),
(TYPE_USER_DENGUE, "Dengue Fever Symptoms", "mdi:alert", "reports"),
(TYPE_USER_FLU, "Flu Symptoms", "mdi:alert", "reports"),
(TYPE_USER_LEPTO, "Leptospirosis Symptoms", "mdi:alert", "reports"),
(TYPE_USER_NO_SYMPTOMS, "No Symptoms", "mdi:alert", "reports"),
(TYPE_USER_SYMPTOMS, "Flu-like Symptoms", "mdi:alert", "reports"),
(TYPE_USER_TOTAL, "Total Symptoms", "mdi:alert", "reports"),
],
}

View File

@ -1,8 +1,9 @@
{
"domain": "flunearyou",
"name": "Flu Near You",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/flunearyou",
"requirements": ["pyflunearyou==1.0.3"],
"requirements": ["pyflunearyou==1.0.7"],
"dependencies": [],
"codeowners": ["@bachya"]
}

View File

@ -1,25 +1,24 @@
"""Support for user- and CDC-based flu info sensors from Flu Near You."""
from datetime import timedelta
import logging
from pyflunearyou import Client
from pyflunearyou.errors import FluNearYouError
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
ATTR_ATTRIBUTION,
ATTR_STATE,
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_MONITORED_CONDITIONS,
)
from homeassistant.helpers import aiohttp_client
import homeassistant.helpers.config_validation as cv
from homeassistant.const import ATTR_ATTRIBUTION, ATTR_STATE
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
_LOGGER = logging.getLogger(__name__)
from .const import (
CATEGORY_CDC_REPORT,
CATEGORY_USER_REPORT,
DATA_CLIENT,
DOMAIN,
SENSORS,
TOPIC_UPDATE,
TYPE_USER_CHICK,
TYPE_USER_DENGUE,
TYPE_USER_FLU,
TYPE_USER_LEPTO,
TYPE_USER_NO_SYMPTOMS,
TYPE_USER_SYMPTOMS,
TYPE_USER_TOTAL,
)
ATTR_CITY = "city"
ATTR_REPORTED_DATE = "reported_date"
@ -31,94 +30,46 @@ ATTR_ZIP_CODE = "zip_code"
DEFAULT_ATTRIBUTION = "Data provided by Flu Near You"
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10)
SCAN_INTERVAL = timedelta(minutes=30)
CATEGORY_CDC_REPORT = "cdc_report"
CATEGORY_USER_REPORT = "user_report"
TYPE_CDC_LEVEL = "level"
TYPE_CDC_LEVEL2 = "level2"
TYPE_USER_CHICK = "chick"
TYPE_USER_DENGUE = "dengue"
TYPE_USER_FLU = "flu"
TYPE_USER_LEPTO = "lepto"
TYPE_USER_NO_SYMPTOMS = "none"
TYPE_USER_SYMPTOMS = "symptoms"
TYPE_USER_TOTAL = "total"
EXTENDED_TYPE_MAPPING = {
TYPE_USER_FLU: "ili",
TYPE_USER_NO_SYMPTOMS: "no_symptoms",
TYPE_USER_TOTAL: "total_surveys",
}
SENSORS = {
CATEGORY_CDC_REPORT: [
(TYPE_CDC_LEVEL, "CDC Level", "mdi:biohazard", None),
(TYPE_CDC_LEVEL2, "CDC Level 2", "mdi:biohazard", None),
],
CATEGORY_USER_REPORT: [
(TYPE_USER_CHICK, "Avian Flu Symptoms", "mdi:alert", "reports"),
(TYPE_USER_DENGUE, "Dengue Fever Symptoms", "mdi:alert", "reports"),
(TYPE_USER_FLU, "Flu Symptoms", "mdi:alert", "reports"),
(TYPE_USER_LEPTO, "Leptospirosis Symptoms", "mdi:alert", "reports"),
(TYPE_USER_NO_SYMPTOMS, "No Symptoms", "mdi:alert", "reports"),
(TYPE_USER_SYMPTOMS, "Flu-like Symptoms", "mdi:alert", "reports"),
(TYPE_USER_TOTAL, "Total Symptoms", "mdi:alert", "reports"),
],
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Optional(CONF_LATITUDE): cv.latitude,
vol.Optional(CONF_LONGITUDE): cv.longitude,
vol.Required(CONF_MONITORED_CONDITIONS, default=list(SENSORS)): vol.All(
cv.ensure_list, [vol.In(SENSORS)]
),
}
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Flu Near You sensors based on a config entry."""
fny = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id]
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Configure the platform and add the sensors."""
websession = aiohttp_client.async_get_clientsession(hass)
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
fny = FluNearYouData(
Client(websession), latitude, longitude, config[CONF_MONITORED_CONDITIONS]
async_add_entities(
[
FluNearYouSensor(fny, sensor_type, name, category, icon, unit)
for category, sensors in SENSORS.items()
for sensor_type, name, icon, unit in sensors
],
True,
)
await fny.async_update()
sensors = [
FluNearYouSensor(fny, kind, name, category, icon, unit)
for category in config[CONF_MONITORED_CONDITIONS]
for kind, name, icon, unit in SENSORS[category]
]
async_add_entities(sensors, True)
class FluNearYouSensor(Entity):
"""Define a base Flu Near You sensor."""
def __init__(self, fny, kind, name, category, icon, unit):
def __init__(self, fny, sensor_type, name, category, icon, unit):
"""Initialize the sensor."""
self._async_unsub_dispatcher_connect = None
self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
self._category = category
self._fny = fny
self._icon = icon
self._kind = kind
self._name = name
self._sensor_type = sensor_type
self._state = None
self._unit = unit
self.fny = fny
@property
def available(self):
"""Return True if entity is available."""
return bool(self.fny.data[self._category])
return bool(self._fny.data[self._category])
@property
def device_state_attributes(self):
@ -143,19 +94,43 @@ class FluNearYouSensor(Entity):
@property
def unique_id(self):
"""Return a unique, Home Assistant friendly identifier for this entity."""
return f"{self.fny.latitude},{self.fny.longitude}_{self._kind}"
return f"{self._fny.latitude},{self._fny.longitude}_{self._sensor_type}"
@property
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return self._unit
async def async_update(self):
"""Update the sensor."""
await self.fny.async_update()
async def async_added_to_hass(self):
"""Register callbacks."""
cdc_data = self.fny.data.get(CATEGORY_CDC_REPORT)
user_data = self.fny.data.get(CATEGORY_USER_REPORT)
@callback
def update():
"""Update the state."""
self.update_from_latest_data()
self.async_write_ha_state()
self._async_unsub_dispatcher_connect = async_dispatcher_connect(
self.hass, TOPIC_UPDATE, update
)
await self._fny.async_register_api_interest(self._sensor_type)
self.update_from_latest_data()
async def async_will_remove_from_hass(self) -> None:
"""Disconnect dispatcher listener when removed."""
if self._async_unsub_dispatcher_connect:
self._async_unsub_dispatcher_connect()
self._async_unsub_dispatcher_connect = None
self._fny.async_deregister_api_interest(self._sensor_type)
@callback
def update_from_latest_data(self):
"""Update the sensor."""
cdc_data = self._fny.data.get(CATEGORY_CDC_REPORT)
user_data = self._fny.data.get(CATEGORY_USER_REPORT)
if self._category == CATEGORY_CDC_REPORT and cdc_data:
self._attrs.update(
@ -164,7 +139,7 @@ class FluNearYouSensor(Entity):
ATTR_STATE: cdc_data["name"],
}
)
self._state = cdc_data[self._kind]
self._state = cdc_data[self._sensor_type]
elif self._category == CATEGORY_USER_REPORT and user_data:
self._attrs.update(
{
@ -176,10 +151,10 @@ class FluNearYouSensor(Entity):
}
)
if self._kind in user_data["state"]["data"]:
states_key = self._kind
elif self._kind in EXTENDED_TYPE_MAPPING:
states_key = EXTENDED_TYPE_MAPPING[self._kind]
if self._sensor_type in user_data["state"]["data"]:
states_key = self._sensor_type
elif self._sensor_type in EXTENDED_TYPE_MAPPING:
states_key = EXTENDED_TYPE_MAPPING[self._sensor_type]
self._attrs[ATTR_STATE_REPORTS_THIS_WEEK] = user_data["state"]["data"][
states_key
@ -188,7 +163,7 @@ class FluNearYouSensor(Entity):
"last_week_data"
][states_key]
if self._kind == TYPE_USER_TOTAL:
if self._sensor_type == TYPE_USER_TOTAL:
self._state = sum(
v
for k, v in user_data["local"].items()
@ -202,32 +177,4 @@ class FluNearYouSensor(Entity):
)
)
else:
self._state = user_data["local"][self._kind]
class FluNearYouData:
"""Define a data object to retrieve info from Flu Near You."""
def __init__(self, client, latitude, longitude, sensor_types):
"""Initialize."""
self._client = client
self._sensor_types = sensor_types
self.data = {}
self.latitude = latitude
self.longitude = longitude
@Throttle(MIN_TIME_BETWEEN_UPDATES)
async def async_update(self):
"""Update Flu Near You data."""
for key, method in [
(CATEGORY_CDC_REPORT, self._client.cdc_reports.status_by_coordinates),
(CATEGORY_USER_REPORT, self._client.user_reports.status_by_coordinates),
]:
if key in self._sensor_types:
try:
self.data[key] = await method(self.latitude, self.longitude)
except FluNearYouError as err:
_LOGGER.error('There was an error with "%s" data: %s', key, err)
self.data[key] = {}
_LOGGER.debug("New data stored: %s", self.data)
self._state = user_data["local"][self._sensor_type]

View File

@ -0,0 +1,21 @@
{
"config": {
"title": "Flu Near You",
"step": {
"user": {
"title": "Configure Flu Near You",
"description": "Monitor user-based and CDC repots for a pair of coordinates.",
"data": {
"latitude": "Latitude",
"longitude": "Longitude"
}
}
},
"error": {
"general_error": "There was an unknown error."
},
"abort": {
"already_configured": "These coordinates are already registered."
}
}
}

View File

@ -31,6 +31,7 @@ FLOWS = [
"elkm1",
"emulated_roku",
"esphome",
"flunearyou",
"freebox",
"garmin_connect",
"gdacs",

View File

@ -1281,7 +1281,7 @@ pyflic-homeassistant==0.4.dev0
pyflume==0.3.0
# homeassistant.components.flunearyou
pyflunearyou==1.0.3
pyflunearyou==1.0.7
# homeassistant.components.futurenow
pyfnip==0.2

View File

@ -493,6 +493,9 @@ pyeverlights==0.1.0
# homeassistant.components.fido
pyfido==2.1.1
# homeassistant.components.flunearyou
pyflunearyou==1.0.7
# homeassistant.components.fritzbox
pyfritzhome==0.4.0

View File

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

View File

@ -0,0 +1,87 @@
"""Define tests for the flunearyou config flow."""
from asynctest import patch
from pyflunearyou.errors import FluNearYouError
from homeassistant import data_entry_flow
from homeassistant.components.flunearyou import DOMAIN
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
from tests.common import MockConfigEntry
async def test_duplicate_error(hass):
"""Test that an error is shown when duplicates are added."""
conf = {CONF_LATITUDE: "51.528308", CONF_LONGITUDE: "-0.3817765"}
MockConfigEntry(
domain=DOMAIN, unique_id="51.528308, -0.3817765", data=conf
).add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=conf
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
async def test_general_error(hass):
"""Test that an error is shown on a library error."""
conf = {CONF_LATITUDE: "51.528308", CONF_LONGITUDE: "-0.3817765"}
with patch(
"pyflunearyou.cdc.CdcReport.status_by_coordinates", side_effect=FluNearYouError,
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=conf
)
assert result["errors"] == {"base": "general_error"}
async def test_show_form(hass):
"""Test that the form is served with no input."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
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_LATITUDE: "51.528308", CONF_LONGITUDE: "-0.3817765"}
with patch(
"homeassistant.components.flunearyou.async_setup_entry", return_value=True
), patch("pyflunearyou.cdc.CdcReport.status_by_coordinates"):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=conf
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "51.528308, -0.3817765"
assert result["data"] == {
CONF_LATITUDE: "51.528308",
CONF_LONGITUDE: "-0.3817765",
}
async def test_step_user(hass):
"""Test that the user step works."""
conf = {CONF_LATITUDE: "51.528308", CONF_LONGITUDE: "-0.3817765"}
with patch(
"homeassistant.components.flunearyou.async_setup_entry", return_value=True
), patch("pyflunearyou.cdc.CdcReport.status_by_coordinates"):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=conf
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "51.528308, -0.3817765"
assert result["data"] == {
CONF_LATITUDE: "51.528308",
CONF_LONGITUDE: "-0.3817765",
}