diff --git a/homeassistant/components/mazda/__init__.py b/homeassistant/components/mazda/__init__.py index 1fd0c3bd618..2af4e46bb1a 100644 --- a/homeassistant/components/mazda/__init__.py +++ b/homeassistant/components/mazda/__init__.py @@ -43,6 +43,7 @@ PLATFORMS = [ Platform.DEVICE_TRACKER, Platform.LOCK, Platform.SENSOR, + Platform.SWITCH, ] @@ -120,6 +121,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: service_call.service, ) + if service_call.service in ("start_charging", "stop_charging"): + _LOGGER.warning( + "The mazda.%s service is deprecated and has been replaced by a switch entity; " + "Please use the charging switch entity instead", + service_call.service, + ) + api_method = getattr(api_client, service_call.service) try: if service_call.service == "send_poi": @@ -213,17 +221,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # 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 - ) + hass.services.async_register( + DOMAIN, + service, + async_handle_service_call, + schema=service_schema_send_poi if service == "send_poi" else service_schema, + ) return True diff --git a/homeassistant/components/mazda/switch.py b/homeassistant/components/mazda/switch.py new file mode 100644 index 00000000000..3ab3028425f --- /dev/null +++ b/homeassistant/components/mazda/switch.py @@ -0,0 +1,70 @@ +"""Platform for Mazda switch integration.""" +from pymazda import Client as MazdaAPIClient + +from homeassistant.components.switch import SwitchEntity +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator + +from . import MazdaEntity +from .const import DATA_CLIENT, DATA_COORDINATOR, DOMAIN + + +async def async_setup_entry( + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up the switch platform.""" + client = hass.data[DOMAIN][config_entry.entry_id][DATA_CLIENT] + coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA_COORDINATOR] + + async_add_entities( + MazdaChargingSwitch(client, coordinator, index) + for index, data in enumerate(coordinator.data) + if data["isElectric"] + ) + + +class MazdaChargingSwitch(MazdaEntity, SwitchEntity): + """Class for the charging switch.""" + + _attr_icon = "mdi:ev-station" + + def __init__( + self, + client: MazdaAPIClient, + coordinator: DataUpdateCoordinator, + index: int, + ) -> None: + """Initialize Mazda charging switch.""" + super().__init__(client, coordinator, index) + + self._attr_name = f"{self.vehicle_name} Charging" + self._attr_unique_id = self.vin + + @property + def is_on(self): + """Return true if the vehicle is charging.""" + return self.data["evStatus"]["chargeInfo"]["charging"] + + async def refresh_status_and_write_state(self): + """Request a status update, retrieve it through the coordinator, and write the state.""" + await self.client.refresh_vehicle_status(self.vehicle_id) + + await self.coordinator.async_request_refresh() + + self.async_write_ha_state() + + async def async_turn_on(self, **kwargs): + """Start charging the vehicle.""" + await self.client.start_charging(self.vehicle_id) + + await self.refresh_status_and_write_state() + + async def async_turn_off(self, **kwargs): + """Stop charging the vehicle.""" + await self.client.stop_charging(self.vehicle_id) + + await self.refresh_status_and_write_state() diff --git a/tests/components/mazda/test_switch.py b/tests/components/mazda/test_switch.py new file mode 100644 index 00000000000..c0fc6f15fb2 --- /dev/null +++ b/tests/components/mazda/test_switch.py @@ -0,0 +1,69 @@ +"""The switch tests for the Mazda Connected Services integration.""" + +from homeassistant.components.switch import ( + DOMAIN as SWITCH_DOMAIN, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + STATE_ON, +) +from homeassistant.const import ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, ATTR_ICON +from homeassistant.helpers import entity_registry as er + +from . import init_integration + + +async def test_switch_setup(hass): + """Test setup of the switch entity.""" + await init_integration(hass, electric_vehicle=True) + + entity_registry = er.async_get(hass) + entry = entity_registry.async_get("switch.my_mazda3_charging") + assert entry + assert entry.unique_id == "JM000000000000000" + + state = hass.states.get("switch.my_mazda3_charging") + assert state + assert state.attributes.get(ATTR_FRIENDLY_NAME) == "My Mazda3 Charging" + assert state.attributes.get(ATTR_ICON) == "mdi:ev-station" + + assert state.state == STATE_ON + + +async def test_start_charging(hass): + """Test turning on the charging switch.""" + client_mock = await init_integration(hass, electric_vehicle=True) + + client_mock.reset_mock() + + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: "switch.my_mazda3_charging"}, + blocking=True, + ) + await hass.async_block_till_done() + + client_mock.start_charging.assert_called_once() + client_mock.refresh_vehicle_status.assert_called_once() + client_mock.get_vehicle_status.assert_called_once() + client_mock.get_ev_vehicle_status.assert_called_once() + + +async def test_stop_charging(hass): + """Test turning off the charging switch.""" + client_mock = await init_integration(hass, electric_vehicle=True) + + client_mock.reset_mock() + + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "switch.my_mazda3_charging"}, + blocking=True, + ) + await hass.async_block_till_done() + + client_mock.stop_charging.assert_called_once() + client_mock.refresh_vehicle_status.assert_called_once() + client_mock.get_vehicle_status.assert_called_once() + client_mock.get_ev_vehicle_status.assert_called_once()