diff --git a/homeassistant/components/mazda/__init__.py b/homeassistant/components/mazda/__init__.py index 1b1e6584a0e..8731fa256a6 100644 --- a/homeassistant/components/mazda/__init__.py +++ b/homeassistant/components/mazda/__init__.py @@ -32,6 +32,12 @@ _LOGGER = logging.getLogger(__name__) PLATFORMS = ["sensor"] +async def with_timeout(task, timeout_seconds=10): + """Run an async task with a timeout.""" + async with async_timeout.timeout(timeout_seconds): + return await task + + async def async_setup(hass: HomeAssistant, config: dict): """Set up the Mazda Connected Services component.""" hass.data[DOMAIN] = {} @@ -69,11 +75,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): async def async_update_data(): """Fetch data from Mazda API.""" - - async def with_timeout(task): - async with async_timeout.timeout(10): - return await task - try: vehicles = await with_timeout(mazda_client.get_vehicles()) diff --git a/homeassistant/components/mazda/config_flow.py b/homeassistant/components/mazda/config_flow.py index 53c08b9bd69..ef0f35e4e8e 100644 --- a/homeassistant/components/mazda/config_flow.py +++ b/homeassistant/components/mazda/config_flow.py @@ -40,15 +40,15 @@ class MazdaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): if user_input is not None: await self.async_set_unique_id(user_input[CONF_EMAIL].lower()) + websession = aiohttp_client.async_get_clientsession(self.hass) + mazda_client = MazdaAPI( + user_input[CONF_EMAIL], + user_input[CONF_PASSWORD], + user_input[CONF_REGION], + websession, + ) try: - websession = aiohttp_client.async_get_clientsession(self.hass) - mazda_client = MazdaAPI( - user_input[CONF_EMAIL], - user_input[CONF_PASSWORD], - user_input[CONF_REGION], - websession, - ) await mazda_client.validate_credentials() except MazdaAuthenticationException: errors["base"] = "invalid_auth" diff --git a/homeassistant/components/mazda/manifest.json b/homeassistant/components/mazda/manifest.json index b3826d42318..c3a05a351c3 100644 --- a/homeassistant/components/mazda/manifest.json +++ b/homeassistant/components/mazda/manifest.json @@ -3,7 +3,7 @@ "name": "Mazda Connected Services", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/mazda", - "requirements": ["pymazda==0.0.8"], + "requirements": ["pymazda==0.0.9"], "codeowners": ["@bdr99"], "quality_scale": "platinum" } \ No newline at end of file diff --git a/homeassistant/components/mazda/sensor.py b/homeassistant/components/mazda/sensor.py index fa03eb7f410..a05291673e8 100644 --- a/homeassistant/components/mazda/sensor.py +++ b/homeassistant/components/mazda/sensor.py @@ -91,7 +91,13 @@ class MazdaFuelDistanceSensor(MazdaEntity): fuel_distance_km = self.coordinator.data[self.index]["status"][ "fuelDistanceRemainingKm" ] - return round(self.hass.config.units.length(fuel_distance_km, LENGTH_KILOMETERS)) + return ( + None + if fuel_distance_km is None + else round( + self.hass.config.units.length(fuel_distance_km, LENGTH_KILOMETERS) + ) + ) class MazdaOdometerSensor(MazdaEntity): @@ -124,7 +130,11 @@ class MazdaOdometerSensor(MazdaEntity): def state(self): """Return the state of the sensor.""" odometer_km = self.coordinator.data[self.index]["status"]["odometerKm"] - return round(self.hass.config.units.length(odometer_km, LENGTH_KILOMETERS)) + return ( + None + if odometer_km is None + else round(self.hass.config.units.length(odometer_km, LENGTH_KILOMETERS)) + ) class MazdaFrontLeftTirePressureSensor(MazdaEntity): @@ -154,11 +164,10 @@ class MazdaFrontLeftTirePressureSensor(MazdaEntity): @property def state(self): """Return the state of the sensor.""" - return round( - self.coordinator.data[self.index]["status"]["tirePressure"][ - "frontLeftTirePressurePsi" - ] - ) + tire_pressure = self.coordinator.data[self.index]["status"]["tirePressure"][ + "frontLeftTirePressurePsi" + ] + return None if tire_pressure is None else round(tire_pressure) class MazdaFrontRightTirePressureSensor(MazdaEntity): @@ -188,11 +197,10 @@ class MazdaFrontRightTirePressureSensor(MazdaEntity): @property def state(self): """Return the state of the sensor.""" - return round( - self.coordinator.data[self.index]["status"]["tirePressure"][ - "frontRightTirePressurePsi" - ] - ) + tire_pressure = self.coordinator.data[self.index]["status"]["tirePressure"][ + "frontRightTirePressurePsi" + ] + return None if tire_pressure is None else round(tire_pressure) class MazdaRearLeftTirePressureSensor(MazdaEntity): @@ -222,11 +230,10 @@ class MazdaRearLeftTirePressureSensor(MazdaEntity): @property def state(self): """Return the state of the sensor.""" - return round( - self.coordinator.data[self.index]["status"]["tirePressure"][ - "rearLeftTirePressurePsi" - ] - ) + tire_pressure = self.coordinator.data[self.index]["status"]["tirePressure"][ + "rearLeftTirePressurePsi" + ] + return None if tire_pressure is None else round(tire_pressure) class MazdaRearRightTirePressureSensor(MazdaEntity): @@ -256,8 +263,7 @@ class MazdaRearRightTirePressureSensor(MazdaEntity): @property def state(self): """Return the state of the sensor.""" - return round( - self.coordinator.data[self.index]["status"]["tirePressure"][ - "rearRightTirePressurePsi" - ] - ) + tire_pressure = self.coordinator.data[self.index]["status"]["tirePressure"][ + "rearRightTirePressurePsi" + ] + return None if tire_pressure is None else round(tire_pressure) diff --git a/requirements_all.txt b/requirements_all.txt index b762b5fd168..b4d6d93bdae 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1518,7 +1518,7 @@ pymailgunner==1.4 pymata-express==1.19 # homeassistant.components.mazda -pymazda==0.0.8 +pymazda==0.0.9 # homeassistant.components.mediaroom pymediaroom==0.6.4.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index aa7afdeb66a..7ff9b14e6d7 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -802,7 +802,7 @@ pymailgunner==1.4 pymata-express==1.19 # homeassistant.components.mazda -pymazda==0.0.8 +pymazda==0.0.9 # homeassistant.components.melcloud pymelcloud==2.5.2 diff --git a/tests/components/mazda/test_init.py b/tests/components/mazda/test_init.py index d0352682f53..ebd118260bc 100644 --- a/tests/components/mazda/test_init.py +++ b/tests/components/mazda/test_init.py @@ -1,18 +1,22 @@ """Tests for the Mazda Connected Services integration.""" +from datetime import timedelta +import json from unittest.mock import patch from pymazda import MazdaAuthenticationException, MazdaException -from homeassistant.components.mazda.const import DATA_COORDINATOR, DOMAIN +from homeassistant.components.mazda.const import DOMAIN from homeassistant.config_entries import ( ENTRY_STATE_LOADED, + ENTRY_STATE_NOT_LOADED, ENTRY_STATE_SETUP_ERROR, ENTRY_STATE_SETUP_RETRY, ) from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, CONF_REGION from homeassistant.core import HomeAssistant +from homeassistant.util import dt as dt_util -from tests.common import MockConfigEntry +from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture from tests.components.mazda import init_integration FIXTURE_USER_INPUT = { @@ -60,10 +64,21 @@ async def test_init_auth_failure(hass: HomeAssistant): async def test_update_auth_failure(hass: HomeAssistant): """Test auth failure during data update.""" + get_vehicles_fixture = json.loads(load_fixture("mazda/get_vehicles.json")) + get_vehicle_status_fixture = json.loads( + load_fixture("mazda/get_vehicle_status.json") + ) + with patch( "homeassistant.components.mazda.MazdaAPI.validate_credentials", return_value=True, - ), patch("homeassistant.components.mazda.MazdaAPI.get_vehicles", return_value={}): + ), patch( + "homeassistant.components.mazda.MazdaAPI.get_vehicles", + return_value=get_vehicles_fixture, + ), patch( + "homeassistant.components.mazda.MazdaAPI.get_vehicle_status", + return_value=get_vehicle_status_fixture, + ): config_entry = MockConfigEntry(domain=DOMAIN, data=FIXTURE_USER_INPUT) config_entry.add_to_hass(hass) @@ -74,15 +89,11 @@ async def test_update_auth_failure(hass: HomeAssistant): assert len(entries) == 1 assert entries[0].state == ENTRY_STATE_LOADED - coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA_COORDINATOR] with patch( - "homeassistant.components.mazda.MazdaAPI.validate_credentials", - side_effect=MazdaAuthenticationException("Login failed"), - ), patch( "homeassistant.components.mazda.MazdaAPI.get_vehicles", side_effect=MazdaAuthenticationException("Login failed"), ): - await coordinator.async_refresh() + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=61)) await hass.async_block_till_done() flows = hass.config_entries.flow.async_progress() @@ -97,4 +108,4 @@ async def test_unload_config_entry(hass: HomeAssistant) -> None: await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() - assert not hass.data.get(DOMAIN) + assert entry.state == ENTRY_STATE_NOT_LOADED