"""Test weather of Google Weather integration.""" from datetime import timedelta from unittest.mock import AsyncMock, patch from freezegun.api import FrozenDateTimeFactory from google_weather_api import GoogleWeatherApiError, WeatherCondition import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.components.google_weather.weather import _CONDITION_MAP from homeassistant.components.homeassistant import ( DOMAIN as HOMEASSISTANT_DOMAIN, SERVICE_UPDATE_ENTITY, ) from homeassistant.components.weather import ( ATTR_CONDITION_CLEAR_NIGHT, ATTR_CONDITION_PARTLYCLOUDY, ATTR_CONDITION_SUNNY, DOMAIN as WEATHER_DOMAIN, SERVICE_GET_FORECASTS, ) from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform from tests.typing import WebSocketGenerator async def test_weather( hass: HomeAssistant, mock_config_entry: MockConfigEntry, entity_registry: er.EntityRegistry, snapshot: SnapshotAssertion, mock_google_weather_api: AsyncMock, ) -> None: """Test states of the weather.""" with patch( "homeassistant.components.google_weather._PLATFORMS", [Platform.WEATHER] ): await hass.config_entries.async_setup(mock_config_entry.entry_id) await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) async def test_availability( hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_google_weather_api: AsyncMock, freezer: FrozenDateTimeFactory, ) -> None: """Ensure entities are marked unavailable when service is offline.""" entity_id = "weather.home" await hass.config_entries.async_setup(mock_config_entry.entry_id) state = hass.states.get(entity_id) assert state assert state.state != STATE_UNAVAILABLE assert state.state == "sunny" mock_google_weather_api.async_get_current_conditions.side_effect = ( GoogleWeatherApiError() ) freezer.tick(timedelta(minutes=15)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state == STATE_UNAVAILABLE # Reset side effect, return a valid response again mock_google_weather_api.async_get_current_conditions.side_effect = None freezer.tick(timedelta(minutes=15)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state != STATE_UNAVAILABLE assert state.state == "sunny" mock_google_weather_api.async_get_current_conditions.assert_called_with( latitude=10.1, longitude=20.1 ) async def test_manual_update_entity( hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_google_weather_api: AsyncMock, ) -> None: """Test manual update entity via service homeassistant/update_entity.""" await hass.config_entries.async_setup(mock_config_entry.entry_id) await async_setup_component(hass, HOMEASSISTANT_DOMAIN, {}) assert mock_google_weather_api.async_get_current_conditions.call_count == 1 mock_google_weather_api.async_get_current_conditions.assert_called_with( latitude=10.1, longitude=20.1 ) await hass.services.async_call( HOMEASSISTANT_DOMAIN, SERVICE_UPDATE_ENTITY, {ATTR_ENTITY_ID: ["weather.home"]}, blocking=True, ) assert mock_google_weather_api.async_get_current_conditions.call_count == 2 @pytest.mark.parametrize( ("api_condition", "is_daytime", "expected_ha_condition"), [ (WeatherCondition.Type.CLEAR, True, ATTR_CONDITION_SUNNY), (WeatherCondition.Type.CLEAR, False, ATTR_CONDITION_CLEAR_NIGHT), (WeatherCondition.Type.PARTLY_CLOUDY, True, ATTR_CONDITION_PARTLYCLOUDY), (WeatherCondition.Type.PARTLY_CLOUDY, False, ATTR_CONDITION_PARTLYCLOUDY), (WeatherCondition.Type.TYPE_UNSPECIFIED, True, "unknown"), ], ) async def test_condition( hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_google_weather_api: AsyncMock, api_condition: WeatherCondition.Type, is_daytime: bool, expected_ha_condition: str, ) -> None: """Test condition mapping.""" current = mock_google_weather_api.async_get_current_conditions current.return_value.weather_condition.type = api_condition current.return_value.is_daytime = is_daytime await hass.config_entries.async_setup(mock_config_entry.entry_id) state = hass.states.get("weather.home") assert state.state == expected_ha_condition def test_all_conditions_mapped() -> None: """Ensure all WeatherCondition.Type enum members are in the _CONDITION_MAP.""" for condition_type in WeatherCondition.Type: assert condition_type in _CONDITION_MAP @pytest.mark.parametrize(("forecast_type"), ["daily", "hourly", "twice_daily"]) async def test_forecast_service( hass: HomeAssistant, mock_config_entry: MockConfigEntry, snapshot: SnapshotAssertion, mock_google_weather_api: AsyncMock, forecast_type, ) -> None: """Test forecast service.""" await hass.config_entries.async_setup(mock_config_entry.entry_id) response = await hass.services.async_call( WEATHER_DOMAIN, SERVICE_GET_FORECASTS, { "entity_id": "weather.home", "type": forecast_type, }, blocking=True, return_response=True, ) assert response == snapshot async def test_forecast_subscription( hass: HomeAssistant, mock_config_entry: MockConfigEntry, hass_ws_client: WebSocketGenerator, freezer: FrozenDateTimeFactory, snapshot: SnapshotAssertion, mock_google_weather_api: AsyncMock, ) -> None: """Test multiple forecast.""" client = await hass_ws_client(hass) await hass.config_entries.async_setup(mock_config_entry.entry_id) await client.send_json_auto_id( { "type": "weather/subscribe_forecast", "forecast_type": "daily", "entity_id": "weather.home", } ) msg = await client.receive_json() assert msg["success"] assert msg["result"] is None subscription_id = msg["id"] msg = await client.receive_json() assert msg["id"] == subscription_id assert msg["type"] == "event" forecast1 = msg["event"]["forecast"] assert forecast1 != [] assert forecast1 == snapshot freezer.tick(timedelta(hours=1) + timedelta(seconds=1)) async_fire_time_changed(hass) await hass.async_block_till_done() msg = await client.receive_json() assert msg["id"] == subscription_id assert msg["type"] == "event" forecast2 = msg["event"]["forecast"] assert forecast2 != [] assert forecast2 == snapshot