Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,10 @@ omit =
homeassistant/components/mediaroom/media_player.py
homeassistant/components/message_bird/notify.py
homeassistant/components/met/weather.py
homeassistant/components/meteo_france/*
homeassistant/components/meteo_france/__init__.py
homeassistant/components/meteo_france/const.py
homeassistant/components/meteo_france/sensor.py
homeassistant/components/meteo_france/weather.py
homeassistant/components/meteoalarm/*
homeassistant/components/metoffice/sensor.py
homeassistant/components/metoffice/weather.py
Expand Down
17 changes: 17 additions & 0 deletions homeassistant/components/meteo_france/.translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"config": {
"abort": {
"already_configured": "City already configured",
"unknown": "Unknown error: please retry later"
},
"step": {
"user": {
"data": {
"city": "City or postal code"
},
"title": "M\u00e9t\u00e9o-France"
}
},
"title": "M\u00e9t\u00e9o-France"
}
}
141 changes: 61 additions & 80 deletions homeassistant/components/meteo_france/__init__.py
Original file line number Diff line number Diff line change
@@ -1,121 +1,102 @@
"""Support for Meteo-France weather data."""
import asyncio
import datetime
import logging

from meteofrance.client import meteofranceClient, meteofranceError
from vigilancemeteo import VigilanceMeteoError, VigilanceMeteoFranceProxy
import voluptuous as vol

from homeassistant.const import CONF_MONITORED_CONDITIONS
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.discovery import load_platform
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
from homeassistant.util import Throttle

from .const import CONF_CITY, DATA_METEO_FRANCE, DOMAIN, SENSOR_TYPES
from .const import CONF_CITY, DOMAIN, PLATFORMS

_LOGGER = logging.getLogger(__name__)

SCAN_INTERVAL = datetime.timedelta(minutes=5)


def has_all_unique_cities(value):
Comment thread
Quentame marked this conversation as resolved.
"""Validate that all cities are unique."""
cities = [location[CONF_CITY] for location in value]
vol.Schema(vol.Unique())(cities)
return value

CITY_SCHEMA = vol.Schema({vol.Required(CONF_CITY): cv.string})

CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.All(
cv.ensure_list,
[
vol.Schema(
{
vol.Required(CONF_CITY): cv.string,
vol.Optional(CONF_MONITORED_CONDITIONS): vol.All(
cv.ensure_list, [vol.In(SENSOR_TYPES)]
),
}
)
],
has_all_unique_cities,
)
},
extra=vol.ALLOW_EXTRA,
{DOMAIN: vol.Schema(vol.All(cv.ensure_list, [CITY_SCHEMA]))}, extra=vol.ALLOW_EXTRA,
)


def setup(hass, config):
"""Set up the Meteo-France component."""
hass.data[DATA_METEO_FRANCE] = {}
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
"""Set up Meteo-France from legacy config file."""

# Check if at least weather alert have to be monitored for one location.
need_weather_alert_watcher = False
for location in config[DOMAIN]:
if (
CONF_MONITORED_CONDITIONS in location
and "weather_alert" in location[CONF_MONITORED_CONDITIONS]
):
need_weather_alert_watcher = True
conf = config.get(DOMAIN)
if conf is None:
return True

# If weather alert monitoring is expected initiate a client to be used by
# all weather_alert entities.
if need_weather_alert_watcher:
_LOGGER.debug("Weather Alert monitoring expected. Loading vigilancemeteo")

weather_alert_client = VigilanceMeteoFranceProxy()
try:
weather_alert_client.update_data()
except VigilanceMeteoError as exp:
_LOGGER.error(
"Unexpected error when creating the vigilance_meteoFrance proxy: %s ",
exp,
for city_conf in conf:
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=city_conf.copy()
)
else:
weather_alert_client = None
hass.data[DATA_METEO_FRANCE]["weather_alert_client"] = weather_alert_client
)

for location in config[DOMAIN]:
return True

city = location[CONF_CITY]

try:
client = meteofranceClient(city)
except meteofranceError as exp:
_LOGGER.error(
"Unexpected error when creating the meteofrance proxy: %s", exp
)
return
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
"""Set up an Meteo-France account from a config entry."""
hass.data.setdefault(DOMAIN, {})

client.need_rain_forecast = bool(
CONF_MONITORED_CONDITIONS in location
and "next_rain" in location[CONF_MONITORED_CONDITIONS]
# Weather alert
weather_alert_client = await hass.async_add_executor_job(VigilanceMeteoFranceProxy)
try:
weather_alert_client.update_data()
Comment thread
Quentame marked this conversation as resolved.
Outdated
except VigilanceMeteoError as exp:
_LOGGER.error(
"Unexpected error when creating the vigilance_meteoFrance proxy: %s ", exp
)
return False
hass.data[DOMAIN]["weather_alert_client"] = weather_alert_client

# Weather
city = entry.data[CONF_CITY]
try:
client = await hass.async_add_executor_job(meteofranceClient, city)
except meteofranceError as exp:
_LOGGER.error("Unexpected error when creating the meteofrance proxy: %s", exp)
return False

hass.data[DOMAIN][city] = MeteoFranceUpdater(client)
hass.data[DOMAIN][city].update()
Comment thread
Quentame marked this conversation as resolved.
Outdated

for platform in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, platform)
)
_LOGGER.debug("meteo_france sensor platform loaded for %s", city)
return True

hass.data[DATA_METEO_FRANCE][city] = MeteoFranceUpdater(client)
hass.data[DATA_METEO_FRANCE][city].update()

if CONF_MONITORED_CONDITIONS in location:
monitored_conditions = location[CONF_MONITORED_CONDITIONS]
_LOGGER.debug("meteo_france sensor platform loaded for %s", city)
load_platform(
hass,
"sensor",
DOMAIN,
{CONF_CITY: city, CONF_MONITORED_CONDITIONS: monitored_conditions},
config,
)

load_platform(hass, "weather", DOMAIN, {CONF_CITY: city}, config)
async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry):
"""Unload a config entry."""
unload_ok = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(entry, platform)
for platform in PLATFORMS
]
)
)
if unload_ok:
hass.data[DOMAIN].pop(entry.data[CONF_CITY])

return True
return unload_ok


class MeteoFranceUpdater:
"""Update data from Meteo-France."""

def __init__(self, client):
def __init__(self, client: meteofranceClient):
"""Initialize the data object."""
self._client = client

Expand Down
63 changes: 63 additions & 0 deletions homeassistant/components/meteo_france/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Config flow to configure the Meteo-France integration."""
import logging

from meteofrance.client import meteofranceClient, meteofranceError
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.data_entry_flow import AbortFlow

from .const import CONF_CITY
from .const import DOMAIN # pylint: disable=unused-import

_LOGGER = logging.getLogger(__name__)


class MeteoFranceFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a Meteo-France config flow."""

VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL

def _show_setup_form(self, user_input=None, errors=None):
"""Show the setup form to the user."""

if user_input is None:
user_input = {}

return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{vol.Required(CONF_CITY, default=user_input.get(CONF_CITY, "")): str}
),
errors=errors or {},
)

async def async_step_user(self, user_input=None):
"""Handle a flow initiated by the user."""
errors = {}

if user_input is None:
return self._show_setup_form(user_input, errors)

city = user_input[CONF_CITY] # Might be a city name or a postal code
city_name = None

try:
client = await self.hass.async_add_executor_job(meteofranceClient, city)
city_name = client.get_data()["name"]
except meteofranceError as exp:
_LOGGER.error(
"Unexpected error when creating the meteofrance proxy: %s", exp
)
raise AbortFlow("unknown")
Comment thread
Quentame marked this conversation as resolved.
Outdated

# Check if already configured
await self.async_set_unique_id(city_name)
self._abort_if_unique_id_configured()

return self.async_create_entry(title=city_name, data={CONF_CITY: city_name})

async def async_step_import(self, user_input):
"""Import a config entry."""
return await self.async_step_user(user_input)
2 changes: 1 addition & 1 deletion homeassistant/components/meteo_france/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from homeassistant.const import TEMP_CELSIUS

DOMAIN = "meteo_france"
DATA_METEO_FRANCE = "data_meteo_france"
PLATFORMS = ["sensor", "weather"]
ATTRIBUTION = "Data provided by Météo-France"

CONF_CITY = "city"
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/meteo_france/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"domain": "meteo_france",
"name": "Météo-France",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/meteo_france",
"requirements": ["meteofrance==0.3.7", "vigilancemeteo==3.0.0"],
"dependencies": [],
Comment thread
Quentame marked this conversation as resolved.
Expand Down
Loading