Пример #1
0
    def __init__(
        self,
        hass: HomeAssistant,
        session: ClientSession,
        api_key: str,
        location_key: str,
        forecast: bool,
    ) -> None:
        """Initialize."""
        self.location_key = location_key
        self.forecast = forecast
        self.is_metric = hass.config.units.is_metric
        self.accuweather = AccuWeather(api_key, session, location_key=self.location_key)

        # Enabling the forecast download increases the number of requests per data
        # update, we use 40 minutes for current condition only and 80 minutes for
        # current condition and forecast as update interval to not exceed allowed number
        # of requests. We have 50 requests allowed per day, so we use 36 and leave 14 as
        # a reserve for restarting HA.
        update_interval = timedelta(minutes=40)
        if self.forecast:
            update_interval *= 2
        _LOGGER.debug("Data will be update every %s", update_interval)

        super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=update_interval)
Пример #2
0
async def test_get_location():
    """Test with valid location data."""
    with open("tests/data/location_data.json") as file:
        location_data = json.load(file)

    session = aiohttp.ClientSession()

    with aioresponses() as session_mock:
        # pylint:disable=line-too-long
        session_mock.get(
            "https://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=32-character-string-1234567890qw&q=52.0677904%252C19.4795644",
            payload=location_data,
            headers=HEADERS,
        )
        accuweather = AccuWeather(VALID_API_KEY,
                                  session,
                                  latitude=LATITUDE,
                                  longitude=LONGITUDE)
        await accuweather.async_get_location()

    await session.close()

    assert accuweather.location_name == "Piątek"
    assert accuweather.location_key == "268068"
    assert accuweather.requests_remaining == 23
Пример #3
0
async def test_api_error():
    """Test with API error"""
    payload = {
        "Code": "ServiceError",
        "Message": "API error.",
    }

    session = aiohttp.ClientSession()

    with aioresponses() as session_mock:
        # pylint:disable=line-too-long
        session_mock.get(
            "https://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=32-character-string-1234567890qw&q=52.0677904%252C19.4795644",
            payload=payload,
            status=404,
        )
        accuweather = AccuWeather(VALID_API_KEY,
                                  session,
                                  latitude=LATITUDE,
                                  longitude=LONGITUDE)
        try:
            await accuweather.async_get_location()
        except ApiError as error:
            assert str(
                error.status) == "Invalid response from AccuWeather API: 404"

    await session.close()
Пример #4
0
async def test_requests_exceeded_error():
    """Test with requests exceeded error"""
    payload = {
        "Code": "ServiceUnavailable",
        "Message": "The allowed number of requests has been exceeded.",
    }

    session = aiohttp.ClientSession()

    with aioresponses() as session_mock:
        # pylint:disable=line-too-long
        session_mock.get(
            "https://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=32-character-string-1234567890qw&q=52.0677904%252C19.4795644",
            payload=payload,
            status=503,
        )
        accuweather = AccuWeather(VALID_API_KEY,
                                  session,
                                  latitude=LATITUDE,
                                  longitude=LONGITUDE)
        try:
            await accuweather.async_get_location()
        except RequestsExceededError as error:
            assert (str(error.status) ==
                    "The allowed number of requests has been exceeded")

    await session.close()
Пример #5
0
async def main():
    async with ClientSession() as websession:
        try:
            accuweather = AccuWeather(API_KEY,
                                      websession,
                                      latitude=LATITUDE,
                                      longitude=LONGITUDE)
            current_conditions = await accuweather.async_get_current_conditions(
            )
            forecast = await accuweather.async_get_forecast(metric=True)
        except (
                ApiError,
                InvalidApiKeyError,
                InvalidCoordinatesError,
                ClientError,
                RequestsExceededError,
        ) as error:
            print(f"Error: {error}")
        else:
            print(
                f"Location: {accuweather.location_name} ({accuweather.location_key})"
            )
            print(f"Requests remaining: {accuweather.requests_remaining}")
            print(f"Current: {current_conditions}")
            print(f"Forecast: {forecast}")
Пример #6
0
async def test_invalid_coordinates_2():
    """Test with invalid coordinates."""
    async with ClientSession() as session:
        try:
            AccuWeather(VALID_API_KEY,
                        session,
                        latitude=199.99,
                        longitude=90.0)
        except InvalidCoordinatesError as error:
            assert str(error.status) == "Your coordinates are invalid"
Пример #7
0
    async def async_step_user(
        self, user_input: dict[str, Any] | None = None
    ) -> FlowResult:
        """Handle a flow initialized by the user."""
        # Under the terms of use of the API, one user can use one free API key. Due to
        # the small number of requests allowed, we only allow one integration instance.
        if self._async_current_entries():
            return self.async_abort(reason="single_instance_allowed")

        errors = {}

        if user_input is not None:
            websession = async_get_clientsession(self.hass)
            try:
                async with timeout(10):
                    accuweather = AccuWeather(
                        user_input[CONF_API_KEY],
                        websession,
                        latitude=user_input[CONF_LATITUDE],
                        longitude=user_input[CONF_LONGITUDE],
                    )
                    await accuweather.async_get_location()
            except (ApiError, ClientConnectorError, asyncio.TimeoutError, ClientError):
                errors["base"] = "cannot_connect"
            except InvalidApiKeyError:
                errors[CONF_API_KEY] = "invalid_api_key"
            except RequestsExceededError:
                errors[CONF_API_KEY] = "requests_exceeded"
            else:
                await self.async_set_unique_id(
                    accuweather.location_key, raise_on_progress=False
                )

                return self.async_create_entry(
                    title=user_input[CONF_NAME], data=user_input
                )

        return self.async_show_form(
            step_id="user",
            data_schema=vol.Schema(
                {
                    vol.Required(CONF_API_KEY): str,
                    vol.Optional(
                        CONF_LATITUDE, default=self.hass.config.latitude
                    ): cv.latitude,
                    vol.Optional(
                        CONF_LONGITUDE, default=self.hass.config.longitude
                    ): cv.longitude,
                    vol.Optional(
                        CONF_NAME, default=self.hass.config.location_name
                    ): str,
                }
            ),
            errors=errors,
        )
Пример #8
0
async def main():
    async with ClientSession() as web_session:
        accuweather = AccuWeather(
            API_KEY, web_session, latitude=LATITUDE, longitude=LONGITUDE
        )
        current_conditions = await accuweather.async_get_current_conditions()
        forecast = await accuweather.async_get_forecast(metric=True)

        # print(f"Location: {accuweather.location_name} ({accuweather.location_key})")
        print(f"Requests remaining: {accuweather.requests_remaining}")
        print(f"Current: {current_conditions}")
Пример #9
0
async def test_invalid_api_key_1():
    """Test with invalid API key."""
    async with ClientSession() as session:
        try:
            AccuWeather(INVALID_API_KEY,
                        session,
                        latitude=LATITUDE,
                        longitude=LONGITUDE)
        except InvalidApiKeyError as error:
            assert (str(error.status) ==
                    "Your API Key must be a 32-character hexadecimal string")
Пример #10
0
async def test_invalid_api_key_2():
    """Test with invalid API key."""
    session = aiohttp.ClientSession()

    with aioresponses() as session_mock:
        # pylint:disable=line-too-long
        session_mock.get(
            "https://dataservice.accuweather.com/currentconditions/v1/268068?apikey=32-character-string-1234567890qw&details=true",
            status=401,
        )
        accuweather = AccuWeather(VALID_API_KEY,
                                  session,
                                  location_key=LOCATION_KEY)
        try:
            await accuweather.async_get_current_conditions()
        except InvalidApiKeyError as error:
            assert str(error.status) == "Invalid API key"

    await session.close()
Пример #11
0
    def __init__(
        self,
        hass: HomeAssistant,
        session: ClientSession,
        api_key: str,
        location_key: str,
        forecast: bool,
        name: str,
    ) -> None:
        """Initialize."""
        self.location_key = location_key
        self.forecast = forecast
        self.accuweather = AccuWeather(api_key,
                                       session,
                                       location_key=location_key)
        self.device_info = DeviceInfo(
            entry_type=DeviceEntryType.SERVICE,
            identifiers={(DOMAIN, location_key)},
            manufacturer=MANUFACTURER,
            name=name,
            # You don't need to provide specific details for the URL,
            # so passing in _ characters is fine if the location key
            # is correct
            configuration_url=("http://accuweather.com/en/"
                               f"_/_/{location_key}/"
                               f"weather-forecast/{location_key}/"),
        )

        # Enabling the forecast download increases the number of requests per data
        # update, we use 40 minutes for current condition only and 80 minutes for
        # current condition and forecast as update interval to not exceed allowed number
        # of requests. We have 50 requests allowed per day, so we use 36 and leave 14 as
        # a reserve for restarting HA.
        update_interval = timedelta(minutes=40)
        if self.forecast:
            update_interval *= 2
        _LOGGER.debug("Data will be update every %s", update_interval)

        super().__init__(hass,
                         _LOGGER,
                         name=DOMAIN,
                         update_interval=update_interval)
Пример #12
0
    def __init__(self, hass, session, api_key, location_key, forecast: bool):
        """Initialize."""
        self.location_key = location_key
        self.forecast = forecast
        self.is_metric = hass.config.units.is_metric
        self.accuweather = AccuWeather(api_key,
                                       session,
                                       location_key=self.location_key)

        # Enabling the forecast download increases the number of requests per data
        # update, we use 32 minutes for current condition only and 64 minutes for
        # current condition and forecast as update interval to not exceed allowed number
        # of requests. We have 50 requests allowed per day, so we use 45 and leave 5 as
        # a reserve for restarting HA.
        update_interval = (timedelta(
            minutes=64) if self.forecast else timedelta(minutes=32))
        _LOGGER.debug("Data will be update every %s", update_interval)

        super().__init__(hass,
                         _LOGGER,
                         name=DOMAIN,
                         update_interval=update_interval)
Пример #13
0
async def test_get_current_conditions():
    """Test with valid current condition data."""
    with open("tests/data/current_condition_data.json") as file:
        current_condition_data = json.load(file)
    with open("tests/data/location_data.json") as file:
        location_data = json.load(file)

    session = aiohttp.ClientSession()

    with aioresponses() as session_mock:
        # pylint:disable=line-too-long
        session_mock.get(
            "https://dataservice.accuweather.com/currentconditions/v1/268068?apikey=32-character-string-1234567890qw&details=true",
            payload=current_condition_data,
            headers=HEADERS,
        )
        session_mock.get(
            "https://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=32-character-string-1234567890qw&q=52.0677904%252C19.4795644",
            payload=location_data,
            headers=HEADERS,
        )
        accuweather = AccuWeather(VALID_API_KEY,
                                  session,
                                  latitude=LATITUDE,
                                  longitude=LONGITUDE)
        current_conditions = await accuweather.async_get_current_conditions()

    await session.close()

    assert current_conditions["WeatherIcon"] == 7
    assert isinstance(current_conditions["HasPrecipitation"], bool)
    assert not current_conditions["HasPrecipitation"]
    assert not current_conditions["PrecipitationType"]
    assert current_conditions["Temperature"]["Metric"]["Value"] == 23.1
    assert current_conditions["Temperature"]["Metric"]["Unit"] == "C"
    assert current_conditions["Temperature"]["Imperial"]["Value"] == 74
    assert current_conditions["Temperature"]["Imperial"]["Unit"] == "F"
    assert accuweather.requests_remaining == 23
Пример #14
0
async def test_get_forecast():
    """Test with valid forecast data."""
    with open("tests/data/forecast_data.json") as file:
        forecast_data = json.load(file)
    with open("tests/data/location_data.json") as file:
        location_data = json.load(file)

    session = aiohttp.ClientSession()

    with aioresponses() as session_mock:
        # pylint:disable=line-too-long
        session_mock.get(
            "https://dataservice.accuweather.com/forecasts/v1/daily/5day/268068?apikey=32-character-string-1234567890qw&details=true&metric=True",
            payload=forecast_data,
            headers=HEADERS,
        )
        session_mock.get(
            "https://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=32-character-string-1234567890qw&q=52.0677904%252C19.4795644",
            payload=location_data,
            headers=HEADERS,
        )

        accuweather = AccuWeather(VALID_API_KEY,
                                  session,
                                  latitude=LATITUDE,
                                  longitude=LONGITUDE)
        forecast = await accuweather.async_get_forecast()

    await session.close()

    assert forecast[0]["IconDay"] == 15
    assert forecast[0]["PrecipitationProbabilityDay"] == 57
    assert forecast[0]["WindDay"]["Speed"]["Value"] == 13.0
    assert forecast[0]["TemperatureMax"]["Value"] == 24.8
    assert forecast[0]["TemperatureMax"]["Unit"] == "C"
    assert forecast[0]["Ozone"]["Value"] == 23
    assert accuweather.requests_remaining == 23