mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 12:47:08 +00:00
Add services for Mazda integration (#51016)
This commit is contained in:
parent
a8a13da793
commit
a36935dcee
@ -11,12 +11,18 @@ from pymazda import (
|
|||||||
MazdaException,
|
MazdaException,
|
||||||
MazdaTokenExpiredException,
|
MazdaTokenExpiredException,
|
||||||
)
|
)
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, CONF_REGION
|
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, CONF_REGION
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
from homeassistant.exceptions import (
|
||||||
from homeassistant.helpers import aiohttp_client
|
ConfigEntryAuthFailed,
|
||||||
|
ConfigEntryNotReady,
|
||||||
|
HomeAssistantError,
|
||||||
|
)
|
||||||
|
from homeassistant.helpers import aiohttp_client, device_registry
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.update_coordinator import (
|
from homeassistant.helpers.update_coordinator import (
|
||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
DataUpdateCoordinator,
|
DataUpdateCoordinator,
|
||||||
@ -24,7 +30,7 @@ from homeassistant.helpers.update_coordinator import (
|
|||||||
)
|
)
|
||||||
from homeassistant.util.async_ import gather_with_concurrency
|
from homeassistant.util.async_ import gather_with_concurrency
|
||||||
|
|
||||||
from .const import DATA_CLIENT, DATA_COORDINATOR, DOMAIN
|
from .const import DATA_CLIENT, DATA_COORDINATOR, DATA_VEHICLES, DOMAIN, SERVICES
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -59,6 +65,77 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||||||
_LOGGER.error("Error occurred during Mazda login request: %s", ex)
|
_LOGGER.error("Error occurred during Mazda login request: %s", ex)
|
||||||
raise ConfigEntryNotReady from ex
|
raise ConfigEntryNotReady from ex
|
||||||
|
|
||||||
|
async def async_handle_service_call(service_call=None):
|
||||||
|
"""Handle a service call."""
|
||||||
|
# Get device entry from device registry
|
||||||
|
dev_reg = device_registry.async_get(hass)
|
||||||
|
device_id = service_call.data.get("device_id")
|
||||||
|
device_entry = dev_reg.async_get(device_id)
|
||||||
|
|
||||||
|
# Get vehicle VIN from device identifiers
|
||||||
|
mazda_identifiers = [
|
||||||
|
identifier
|
||||||
|
for identifier in device_entry.identifiers
|
||||||
|
if identifier[0] == DOMAIN
|
||||||
|
]
|
||||||
|
vin_identifier = next(iter(mazda_identifiers))
|
||||||
|
vin = vin_identifier[1]
|
||||||
|
|
||||||
|
# Get vehicle ID and API client from hass.data
|
||||||
|
vehicle_id = 0
|
||||||
|
api_client = None
|
||||||
|
for entry_data in hass.data[DOMAIN].values():
|
||||||
|
for vehicle in entry_data[DATA_VEHICLES]:
|
||||||
|
if vehicle["vin"] == vin:
|
||||||
|
vehicle_id = vehicle["id"]
|
||||||
|
api_client = entry_data[DATA_CLIENT]
|
||||||
|
|
||||||
|
if vehicle_id == 0 or api_client is None:
|
||||||
|
raise HomeAssistantError("Vehicle ID not found")
|
||||||
|
|
||||||
|
api_method = getattr(api_client, service_call.service)
|
||||||
|
try:
|
||||||
|
if service_call.service == "send_poi":
|
||||||
|
latitude = service_call.data.get("latitude")
|
||||||
|
longitude = service_call.data.get("longitude")
|
||||||
|
poi_name = service_call.data.get("poi_name")
|
||||||
|
await api_method(vehicle_id, latitude, longitude, poi_name)
|
||||||
|
else:
|
||||||
|
await api_method(vehicle_id)
|
||||||
|
except Exception as ex:
|
||||||
|
_LOGGER.exception("Error occurred during Mazda service call: %s", ex)
|
||||||
|
raise HomeAssistantError(ex) from ex
|
||||||
|
|
||||||
|
def validate_mazda_device_id(device_id):
|
||||||
|
"""Check that a device ID exists in the registry and has at least one 'mazda' identifier."""
|
||||||
|
dev_reg = device_registry.async_get(hass)
|
||||||
|
device_entry = dev_reg.async_get(device_id)
|
||||||
|
|
||||||
|
if device_entry is None:
|
||||||
|
raise vol.Invalid("Invalid device ID")
|
||||||
|
|
||||||
|
mazda_identifiers = [
|
||||||
|
identifier
|
||||||
|
for identifier in device_entry.identifiers
|
||||||
|
if identifier[0] == DOMAIN
|
||||||
|
]
|
||||||
|
if len(mazda_identifiers) < 1:
|
||||||
|
raise vol.Invalid("Device ID is not a Mazda vehicle")
|
||||||
|
|
||||||
|
return device_id
|
||||||
|
|
||||||
|
service_schema = vol.Schema(
|
||||||
|
{vol.Required("device_id"): vol.All(cv.string, validate_mazda_device_id)}
|
||||||
|
)
|
||||||
|
|
||||||
|
service_schema_send_poi = service_schema.extend(
|
||||||
|
{
|
||||||
|
vol.Required("latitude"): cv.latitude,
|
||||||
|
vol.Required("longitude"): cv.longitude,
|
||||||
|
vol.Required("poi_name"): cv.string,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
async def async_update_data():
|
async def async_update_data():
|
||||||
"""Fetch data from Mazda API."""
|
"""Fetch data from Mazda API."""
|
||||||
try:
|
try:
|
||||||
@ -73,6 +150,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||||||
for vehicle, status in zip(vehicles, statuses):
|
for vehicle, status in zip(vehicles, statuses):
|
||||||
vehicle["status"] = status
|
vehicle["status"] = status
|
||||||
|
|
||||||
|
hass.data[DOMAIN][entry.entry_id][DATA_VEHICLES] = vehicles
|
||||||
|
|
||||||
return vehicles
|
return vehicles
|
||||||
except MazdaAuthenticationException as ex:
|
except MazdaAuthenticationException as ex:
|
||||||
raise ConfigEntryAuthFailed("Not authenticated with Mazda API") from ex
|
raise ConfigEntryAuthFailed("Not authenticated with Mazda API") from ex
|
||||||
@ -94,6 +173,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||||||
hass.data[DOMAIN][entry.entry_id] = {
|
hass.data[DOMAIN][entry.entry_id] = {
|
||||||
DATA_CLIENT: mazda_client,
|
DATA_CLIENT: mazda_client,
|
||||||
DATA_COORDINATOR: coordinator,
|
DATA_COORDINATOR: coordinator,
|
||||||
|
DATA_VEHICLES: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fetch initial data so we have data when entities subscribe
|
# Fetch initial data so we have data when entities subscribe
|
||||||
@ -102,12 +182,32 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||||||
# Setup components
|
# Setup components
|
||||||
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
||||||
|
|
||||||
|
# Register services
|
||||||
|
for service in SERVICES:
|
||||||
|
if service == "send_poi":
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN,
|
||||||
|
service,
|
||||||
|
async_handle_service_call,
|
||||||
|
schema=service_schema_send_poi,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN, service, async_handle_service_call, schema=service_schema
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||||
|
|
||||||
|
# Only remove services if it is the last config entry
|
||||||
|
if len(hass.data[DOMAIN]) == 1:
|
||||||
|
for service in SERVICES:
|
||||||
|
hass.services.async_remove(DOMAIN, service)
|
||||||
|
|
||||||
if unload_ok:
|
if unload_ok:
|
||||||
hass.data[DOMAIN].pop(entry.entry_id)
|
hass.data[DOMAIN].pop(entry.entry_id)
|
||||||
|
|
||||||
|
@ -4,5 +4,16 @@ DOMAIN = "mazda"
|
|||||||
|
|
||||||
DATA_CLIENT = "mazda_client"
|
DATA_CLIENT = "mazda_client"
|
||||||
DATA_COORDINATOR = "coordinator"
|
DATA_COORDINATOR = "coordinator"
|
||||||
|
DATA_VEHICLES = "vehicles"
|
||||||
|
|
||||||
MAZDA_REGIONS = {"MNAO": "North America", "MME": "Europe", "MJO": "Japan"}
|
MAZDA_REGIONS = {"MNAO": "North America", "MME": "Europe", "MJO": "Japan"}
|
||||||
|
|
||||||
|
SERVICES = [
|
||||||
|
"send_poi",
|
||||||
|
"start_charging",
|
||||||
|
"start_engine",
|
||||||
|
"stop_charging",
|
||||||
|
"stop_engine",
|
||||||
|
"turn_off_hazard_lights",
|
||||||
|
"turn_on_hazard_lights",
|
||||||
|
]
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Mazda Connected Services",
|
"name": "Mazda Connected Services",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/mazda",
|
"documentation": "https://www.home-assistant.io/integrations/mazda",
|
||||||
"requirements": ["pymazda==0.1.5"],
|
"requirements": ["pymazda==0.1.6"],
|
||||||
"codeowners": ["@bdr99"],
|
"codeowners": ["@bdr99"],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"iot_class": "cloud_polling"
|
"iot_class": "cloud_polling"
|
||||||
|
106
homeassistant/components/mazda/services.yaml
Normal file
106
homeassistant/components/mazda/services.yaml
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
start_engine:
|
||||||
|
name: Start engine
|
||||||
|
description: Start the vehicle engine.
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
name: Vehicle
|
||||||
|
description: The vehicle to start
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
integration: mazda
|
||||||
|
stop_engine:
|
||||||
|
name: Stop engine
|
||||||
|
description: Stop the vehicle engine.
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
name: Vehicle
|
||||||
|
description: The vehicle to stop
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
integration: mazda
|
||||||
|
turn_on_hazard_lights:
|
||||||
|
name: Turn on hazard lights
|
||||||
|
description: Turn on the vehicle hazard lights. The lights will flash briefly and then turn off.
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
name: Vehicle
|
||||||
|
description: The vehicle to turn hazard lights on
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
integration: mazda
|
||||||
|
turn_off_hazard_lights:
|
||||||
|
name: Turn off hazard lights
|
||||||
|
description: Turn off the vehicle hazard lights if they have been manually turned on from inside the vehicle.
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
name: Vehicle
|
||||||
|
description: The vehicle to turn hazard lights off
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
integration: mazda
|
||||||
|
send_poi:
|
||||||
|
name: Send POI
|
||||||
|
description: Send a GPS location to the vehicle's navigation system as a POI (Point of Interest). Requires a navigation SD card installed in the vehicle.
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
name: Vehicle
|
||||||
|
description: The vehicle to send the GPS location to
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
integration: mazda
|
||||||
|
latitude:
|
||||||
|
name: Latitude
|
||||||
|
description: The latitude of the location to send
|
||||||
|
example: 12.34567
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: -90
|
||||||
|
max: 90
|
||||||
|
unit_of_measurement: °
|
||||||
|
mode: box
|
||||||
|
longitude:
|
||||||
|
name: Longitude
|
||||||
|
description: The longitude of the location to send
|
||||||
|
example: -34.56789
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: -180
|
||||||
|
max: 180
|
||||||
|
unit_of_measurement: °
|
||||||
|
mode: box
|
||||||
|
poi_name:
|
||||||
|
name: POI name
|
||||||
|
description: A friendly name for the location
|
||||||
|
example: Work
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
start_charging:
|
||||||
|
name: Start charging
|
||||||
|
description: Start charging the vehicle. For electric vehicles only.
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
name: Vehicle
|
||||||
|
description: The vehicle to start charging
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
integration: mazda
|
||||||
|
stop_charging:
|
||||||
|
name: Stop charging
|
||||||
|
description: Stop charging the vehicle. For electric vehicles only.
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
name: Vehicle
|
||||||
|
description: The vehicle to stop charging
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
integration: mazda
|
@ -1548,7 +1548,7 @@ pymailgunner==1.4
|
|||||||
pymata-express==1.19
|
pymata-express==1.19
|
||||||
|
|
||||||
# homeassistant.components.mazda
|
# homeassistant.components.mazda
|
||||||
pymazda==0.1.5
|
pymazda==0.1.6
|
||||||
|
|
||||||
# homeassistant.components.mediaroom
|
# homeassistant.components.mediaroom
|
||||||
pymediaroom==0.6.4.1
|
pymediaroom==0.6.4.1
|
||||||
|
@ -862,7 +862,7 @@ pymailgunner==1.4
|
|||||||
pymata-express==1.19
|
pymata-express==1.19
|
||||||
|
|
||||||
# homeassistant.components.mazda
|
# homeassistant.components.mazda
|
||||||
pymazda==0.1.5
|
pymazda==0.1.6
|
||||||
|
|
||||||
# homeassistant.components.melcloud
|
# homeassistant.components.melcloud
|
||||||
pymelcloud==2.5.2
|
pymelcloud==2.5.2
|
||||||
|
@ -44,6 +44,13 @@ async def init_integration(hass: HomeAssistant, use_nickname=True) -> MockConfig
|
|||||||
client_mock.get_vehicle_status = AsyncMock(return_value=get_vehicle_status_fixture)
|
client_mock.get_vehicle_status = AsyncMock(return_value=get_vehicle_status_fixture)
|
||||||
client_mock.lock_doors = AsyncMock()
|
client_mock.lock_doors = AsyncMock()
|
||||||
client_mock.unlock_doors = AsyncMock()
|
client_mock.unlock_doors = AsyncMock()
|
||||||
|
client_mock.send_poi = AsyncMock()
|
||||||
|
client_mock.start_charging = AsyncMock()
|
||||||
|
client_mock.start_engine = AsyncMock()
|
||||||
|
client_mock.stop_charging = AsyncMock()
|
||||||
|
client_mock.stop_engine = AsyncMock()
|
||||||
|
client_mock.turn_off_hazard_lights = AsyncMock()
|
||||||
|
client_mock.turn_on_hazard_lights = AsyncMock()
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.mazda.config_flow.MazdaAPI",
|
"homeassistant.components.mazda.config_flow.MazdaAPI",
|
||||||
|
@ -4,8 +4,10 @@ import json
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from pymazda import MazdaAuthenticationException, MazdaException
|
from pymazda import MazdaAuthenticationException, MazdaException
|
||||||
|
import pytest
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.mazda.const import DOMAIN
|
from homeassistant.components.mazda.const import DOMAIN, SERVICES
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_EMAIL,
|
CONF_EMAIL,
|
||||||
@ -14,6 +16,7 @@ from homeassistant.const import (
|
|||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
@ -181,3 +184,130 @@ async def test_device_no_nickname(hass):
|
|||||||
assert reg_device.model == "2021 MAZDA3 2.5 S SE AWD"
|
assert reg_device.model == "2021 MAZDA3 2.5 S SE AWD"
|
||||||
assert reg_device.manufacturer == "Mazda"
|
assert reg_device.manufacturer == "Mazda"
|
||||||
assert reg_device.name == "2021 MAZDA3 2.5 S SE AWD"
|
assert reg_device.name == "2021 MAZDA3 2.5 S SE AWD"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_services(hass):
|
||||||
|
"""Test service calls."""
|
||||||
|
client_mock = await init_integration(hass)
|
||||||
|
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
reg_device = device_registry.async_get_device(
|
||||||
|
identifiers={(DOMAIN, "JM000000000000000")},
|
||||||
|
)
|
||||||
|
device_id = reg_device.id
|
||||||
|
|
||||||
|
for service in SERVICES:
|
||||||
|
service_data = {"device_id": device_id}
|
||||||
|
if service == "send_poi":
|
||||||
|
service_data["latitude"] = 1.2345
|
||||||
|
service_data["longitude"] = 2.3456
|
||||||
|
service_data["poi_name"] = "Work"
|
||||||
|
|
||||||
|
await hass.services.async_call(DOMAIN, service, service_data, blocking=True)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
api_method = getattr(client_mock, service)
|
||||||
|
if service == "send_poi":
|
||||||
|
api_method.assert_called_once_with(12345, 1.2345, 2.3456, "Work")
|
||||||
|
else:
|
||||||
|
api_method.assert_called_once_with(12345)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_service_invalid_device_id(hass):
|
||||||
|
"""Test service call when the specified device ID is invalid."""
|
||||||
|
await init_integration(hass)
|
||||||
|
|
||||||
|
with pytest.raises(vol.error.MultipleInvalid) as err:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN, "start_engine", {"device_id": "invalid"}, blocking=True
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert "Invalid device ID" in str(err.value)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_service_device_id_not_mazda_vehicle(hass):
|
||||||
|
"""Test service call when the specified device ID is not the device ID of a Mazda vehicle."""
|
||||||
|
await init_integration(hass)
|
||||||
|
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
# Create another device and pass its device ID.
|
||||||
|
# Service should fail because device is from wrong domain.
|
||||||
|
other_device = device_registry.async_get_or_create(
|
||||||
|
config_entry_id="test_config_entry_id",
|
||||||
|
identifiers={("OTHER_INTEGRATION", "ID_FROM_OTHER_INTEGRATION")},
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(vol.error.MultipleInvalid) as err:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN, "start_engine", {"device_id": other_device.id}, blocking=True
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert "Device ID is not a Mazda vehicle" in str(err.value)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_service_vehicle_id_not_found(hass):
|
||||||
|
"""Test service call when the vehicle ID is not found."""
|
||||||
|
await init_integration(hass)
|
||||||
|
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
reg_device = device_registry.async_get_device(
|
||||||
|
identifiers={(DOMAIN, "JM000000000000000")},
|
||||||
|
)
|
||||||
|
device_id = reg_device.id
|
||||||
|
|
||||||
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
|
entry_id = entries[0].entry_id
|
||||||
|
|
||||||
|
# Remove vehicle info from hass.data so that vehicle ID will not be found
|
||||||
|
hass.data[DOMAIN][entry_id]["vehicles"] = []
|
||||||
|
|
||||||
|
with pytest.raises(HomeAssistantError) as err:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN, "start_engine", {"device_id": device_id}, blocking=True
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert str(err.value) == "Vehicle ID not found"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_service_mazda_api_error(hass):
|
||||||
|
"""Test the Mazda API raising an error when a service is called."""
|
||||||
|
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=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)
|
||||||
|
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
reg_device = device_registry.async_get_device(
|
||||||
|
identifiers={(DOMAIN, "JM000000000000000")},
|
||||||
|
)
|
||||||
|
device_id = reg_device.id
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.mazda.MazdaAPI.start_engine",
|
||||||
|
side_effect=MazdaException("Test error"),
|
||||||
|
), pytest.raises(HomeAssistantError) as err:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN, "start_engine", {"device_id": device_id}, blocking=True
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert str(err.value) == "Test error"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user