diff --git a/custom_components/snowtire/binary_sensor.py b/custom_components/snowtire/binary_sensor.py index 4a7396c..7da74dd 100644 --- a/custom_components/snowtire/binary_sensor.py +++ b/custom_components/snowtire/binary_sensor.py @@ -20,13 +20,15 @@ ATTR_FORECAST_TEMP_LOW, ATTR_FORECAST_TIME, ATTR_WEATHER_TEMPERATURE, - DOMAIN as WEATHER, + DOMAIN as WEATHER_DOMAIN, SERVICE_GET_FORECASTS, WeatherEntityFeature, ) from homeassistant.const import ( ATTR_SUPPORTED_FEATURES, + CONF_ENTITY_ID, CONF_NAME, + CONF_TYPE, CONF_UNIQUE_ID, EVENT_HOMEASSISTANT_START, UnitOfTemperature, @@ -54,7 +56,7 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend( { - vol.Required(CONF_WEATHER): cv.entity_domain(WEATHER), + vol.Required(CONF_WEATHER): cv.entity_domain(WEATHER_DOMAIN), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_DAYS, default=DEFAULT_DAYS): cv.positive_int, vol.Optional(CONF_UNIQUE_ID): cv.string, @@ -155,33 +157,37 @@ async def async_update( self, ): # pylint: disable=too-many-branches,too-many-statements """Update the sensor state.""" - wdata = self.hass.states.get(self._weather_entity) - - if wdata is None: + wstate = self.hass.states.get(self._weather_entity) + if wstate is None: raise HomeAssistantError( f"Unable to find an entity called {self._weather_entity}" ) + tmpu = self.hass.config.units.temperature_unit + temp = wstate.attributes.get(ATTR_WEATHER_TEMPERATURE) + + wfeatures = wstate.attributes.get(ATTR_SUPPORTED_FEATURES) if ( - wdata.attributes.get(ATTR_SUPPORTED_FEATURES) - is not WeatherEntityFeature.FORECAST_DAILY + not isinstance(wfeatures, WeatherEntityFeature) + or (wfeatures & WeatherEntityFeature.FORECAST_DAILY) == 0 ): raise HomeAssistantError("Weather entity doesn't support 'daily' forecast") - tmpu = self.hass.config.units.temperature_unit - temp = wdata.attributes.get(ATTR_WEATHER_TEMPERATURE) - forecast = await self.hass.services.async_call( - WEATHER, - SERVICE_GET_FORECASTS, - {"type": "daily", "entity_id": [self._weather_entity]}, - blocking=True, - return_response=True, - ) - - if forecast is None: + try: + forecast = await self.hass.services.async_call( + WEATHER_DOMAIN, + SERVICE_GET_FORECASTS, + { + CONF_TYPE: "daily", + CONF_ENTITY_ID: self._weather_entity, + }, + blocking=True, + return_response=True, + ) + except HomeAssistantError as ex: raise HomeAssistantError( "Can't get forecast data! Are you sure it's the weather provider?" - ) + ) from ex _LOGGER.debug("Current temperature %.1f°C", temp) diff --git a/custom_components/snowtire/const.py b/custom_components/snowtire/const.py index f5be263..ede6aac 100644 --- a/custom_components/snowtire/const.py +++ b/custom_components/snowtire/const.py @@ -9,7 +9,7 @@ # Base component constants NAME: Final = "Snowtire Sensor" DOMAIN: Final = "snowtire" -VERSION: Final = "1.4.7" +VERSION: Final = "1.4.8-alpha" ISSUE_URL: Final = "https://github.com/Limych/ha-snowtire/issues" STARTUP_MESSAGE: Final = f""" diff --git a/custom_components/snowtire/manifest.json b/custom_components/snowtire/manifest.json index 9d23354..a720301 100644 --- a/custom_components/snowtire/manifest.json +++ b/custom_components/snowtire/manifest.json @@ -12,5 +12,5 @@ "iot_class": "calculated", "issue_tracker": "https://github.com/Limych/ha-snowtire/issues", "requirements": [], - "version": "1.4.7" + "version": "1.4.8-alpha" } \ No newline at end of file diff --git a/tests/test_binary_sensor.py b/tests/test_binary_sensor.py index 8421596..0f93f97 100644 --- a/tests/test_binary_sensor.py +++ b/tests/test_binary_sensor.py @@ -103,6 +103,67 @@ async def test__temp2c(temp1, temp2): assert SnowtireBinarySensor._temp2c(None, UnitOfTemperature.CELSIUS) is None +async def test_async_update_forecast_fail(hass: HomeAssistant, default_sensor): + """Test sensor update on forecast fail.""" + async_mock_service( + hass, + CONF_WEATHER, + SERVICE_GET_FORECASTS, + supports_response=SupportsResponse.OPTIONAL, + ) + + with raises(HomeAssistantError, match="Unable to find an entity"): + await default_sensor.async_update() + + hass.states.async_set( + MOCK_WEATHER_ENTITY, + "State", + attributes={ + ATTR_WEATHER_TEMPERATURE: -1, + }, + ) + + with raises(HomeAssistantError, match="doesn't support 'daily' forecast"): + await default_sensor.async_update() + + hass.states.async_set( + MOCK_WEATHER_ENTITY, + "State", + attributes={ + ATTR_WEATHER_TEMPERATURE: -1, + ATTR_SUPPORTED_FEATURES: "unexpected", + }, + ) + + with raises(HomeAssistantError, match="doesn't support 'daily' forecast"): + await default_sensor.async_update() + + hass.states.async_set( + MOCK_WEATHER_ENTITY, + "State", + attributes={ + ATTR_WEATHER_TEMPERATURE: -1, + ATTR_SUPPORTED_FEATURES: WeatherEntityFeature.FORECAST_HOURLY, + }, + ) + + with raises(HomeAssistantError, match="doesn't support 'daily' forecast"): + await default_sensor.async_update() + + hass.states.async_set( + MOCK_WEATHER_ENTITY, + "State", + attributes={ + ATTR_WEATHER_TEMPERATURE: -1, + ATTR_SUPPORTED_FEATURES: WeatherEntityFeature.FORECAST_HOURLY + | WeatherEntityFeature.FORECAST_DAILY, + }, + ) + + with raises(HomeAssistantError, match="Can't get forecast data!"): + await default_sensor.async_update() + + async def test_async_update(hass: HomeAssistant, default_sensor): """Test sensor update.""" hass.states._states[MOCK_WEATHER_ENTITY] = State(MOCK_WEATHER_ENTITY, None) @@ -184,35 +245,3 @@ async def test_async_update(hass: HomeAssistant, default_sensor): assert default_sensor.available assert default_sensor.is_on is False assert default_sensor.icon == ICON_SUMMER - - -async def test_async_update_forecast_fail(hass: HomeAssistant, default_sensor): - """Test sensor update on forecast fail.""" - hass.states._states[MOCK_WEATHER_ENTITY] = State(MOCK_WEATHER_ENTITY, None) - - with raises(HomeAssistantError): - await default_sensor.async_update() - - hass.states.async_set(MOCK_WEATHER_ENTITY, "State") - - with raises(HomeAssistantError): - await default_sensor.async_update() - - async_mock_service( - hass, - CONF_WEATHER, - SERVICE_GET_FORECASTS, - supports_response=SupportsResponse.OPTIONAL, - ) - - hass.states.async_set( - MOCK_WEATHER_ENTITY, - "State", - attributes={ - ATTR_WEATHER_TEMPERATURE: -1, - ATTR_SUPPORTED_FEATURES: WeatherEntityFeature.FORECAST_DAILY, - }, - ) - - with raises(HomeAssistantError): - await default_sensor.async_update()