174 lines
6.0 KiB
Python
174 lines
6.0 KiB
Python
"""Support for Renault services."""
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
import logging
|
|
from types import MappingProxyType
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.core import HomeAssistant, ServiceCall
|
|
from homeassistant.helpers import config_validation as cv, device_registry as dr
|
|
|
|
from .const import DOMAIN
|
|
from .renault_hub import RenaultHub
|
|
from .renault_vehicle import RenaultVehicleProxy
|
|
|
|
LOGGER = logging.getLogger(__name__)
|
|
|
|
ATTR_SCHEDULES = "schedules"
|
|
ATTR_TEMPERATURE = "temperature"
|
|
ATTR_VEHICLE = "vehicle"
|
|
ATTR_WHEN = "when"
|
|
|
|
SERVICE_VEHICLE_SCHEMA = vol.Schema(
|
|
{
|
|
vol.Required(ATTR_VEHICLE): cv.string,
|
|
}
|
|
)
|
|
SERVICE_AC_START_SCHEMA = SERVICE_VEHICLE_SCHEMA.extend(
|
|
{
|
|
vol.Required(ATTR_TEMPERATURE): cv.positive_float,
|
|
vol.Optional(ATTR_WHEN): cv.datetime,
|
|
}
|
|
)
|
|
SERVICE_CHARGE_SET_SCHEDULE_DAY_SCHEMA = vol.Schema(
|
|
{
|
|
vol.Required("startTime"): cv.string,
|
|
vol.Required("duration"): cv.positive_int,
|
|
}
|
|
)
|
|
SERVICE_CHARGE_SET_SCHEDULE_SCHEMA = vol.Schema(
|
|
{
|
|
vol.Required("id"): cv.positive_int,
|
|
vol.Optional("activated"): cv.boolean,
|
|
vol.Optional("monday"): vol.Schema(SERVICE_CHARGE_SET_SCHEDULE_DAY_SCHEMA),
|
|
vol.Optional("tuesday"): vol.Schema(SERVICE_CHARGE_SET_SCHEDULE_DAY_SCHEMA),
|
|
vol.Optional("wednesday"): vol.Schema(SERVICE_CHARGE_SET_SCHEDULE_DAY_SCHEMA),
|
|
vol.Optional("thursday"): vol.Schema(SERVICE_CHARGE_SET_SCHEDULE_DAY_SCHEMA),
|
|
vol.Optional("friday"): vol.Schema(SERVICE_CHARGE_SET_SCHEDULE_DAY_SCHEMA),
|
|
vol.Optional("saturday"): vol.Schema(SERVICE_CHARGE_SET_SCHEDULE_DAY_SCHEMA),
|
|
vol.Optional("sunday"): vol.Schema(SERVICE_CHARGE_SET_SCHEDULE_DAY_SCHEMA),
|
|
}
|
|
)
|
|
SERVICE_CHARGE_SET_SCHEDULES_SCHEMA = SERVICE_VEHICLE_SCHEMA.extend(
|
|
{
|
|
vol.Required(ATTR_SCHEDULES): vol.All(
|
|
cv.ensure_list, [SERVICE_CHARGE_SET_SCHEDULE_SCHEMA]
|
|
),
|
|
}
|
|
)
|
|
|
|
SERVICE_AC_CANCEL = "ac_cancel"
|
|
SERVICE_AC_START = "ac_start"
|
|
SERVICE_CHARGE_SET_SCHEDULES = "charge_set_schedules"
|
|
SERVICE_CHARGE_START = "charge_start"
|
|
SERVICES = [
|
|
SERVICE_AC_CANCEL,
|
|
SERVICE_AC_START,
|
|
SERVICE_CHARGE_SET_SCHEDULES,
|
|
SERVICE_CHARGE_START,
|
|
]
|
|
|
|
|
|
def setup_services(hass: HomeAssistant) -> None:
|
|
"""Register the Renault services."""
|
|
|
|
async def ac_cancel(service_call: ServiceCall) -> None:
|
|
"""Cancel A/C."""
|
|
proxy = get_vehicle_proxy(service_call.data)
|
|
|
|
LOGGER.debug("A/C cancel attempt")
|
|
result = await proxy.vehicle.set_ac_stop()
|
|
LOGGER.debug("A/C cancel result: %s", result)
|
|
|
|
async def ac_start(service_call: ServiceCall) -> None:
|
|
"""Start A/C."""
|
|
temperature: float = service_call.data[ATTR_TEMPERATURE]
|
|
when: datetime | None = service_call.data.get(ATTR_WHEN)
|
|
proxy = get_vehicle_proxy(service_call.data)
|
|
|
|
LOGGER.debug("A/C start attempt: %s / %s", temperature, when)
|
|
result = await proxy.vehicle.set_ac_start(temperature, when)
|
|
LOGGER.debug("A/C start result: %s", result.raw_data)
|
|
|
|
async def charge_set_schedules(service_call: ServiceCall) -> None:
|
|
"""Set charge schedules."""
|
|
schedules: list[dict[str, Any]] = service_call.data[ATTR_SCHEDULES]
|
|
proxy = get_vehicle_proxy(service_call.data)
|
|
charge_schedules = await proxy.vehicle.get_charging_settings()
|
|
for schedule in schedules:
|
|
charge_schedules.update(schedule)
|
|
|
|
if TYPE_CHECKING:
|
|
assert charge_schedules.schedules is not None
|
|
LOGGER.debug("Charge set schedules attempt: %s", schedules)
|
|
result = await proxy.vehicle.set_charge_schedules(charge_schedules.schedules)
|
|
LOGGER.debug("Charge set schedules result: %s", result)
|
|
LOGGER.debug(
|
|
"It may take some time before these changes are reflected in your vehicle"
|
|
)
|
|
|
|
async def charge_start(service_call: ServiceCall) -> None:
|
|
"""Start charge."""
|
|
# The Renault start charge service has been replaced by a
|
|
# dedicated button entity and marked as deprecated
|
|
LOGGER.warning(
|
|
"The 'renault.charge_start' service is deprecated and "
|
|
"replaced by a dedicated start charge button entity; please "
|
|
"use that entity to start the charge instead"
|
|
)
|
|
|
|
proxy = get_vehicle_proxy(service_call.data)
|
|
|
|
LOGGER.debug("Charge start attempt")
|
|
result = await proxy.vehicle.set_charge_start()
|
|
LOGGER.debug("Charge start result: %s", result)
|
|
|
|
def get_vehicle_proxy(service_call_data: MappingProxyType) -> RenaultVehicleProxy:
|
|
"""Get vehicle from service_call data."""
|
|
device_registry = dr.async_get(hass)
|
|
device_id = service_call_data[ATTR_VEHICLE]
|
|
device_entry = device_registry.async_get(device_id)
|
|
if device_entry is None:
|
|
raise ValueError(f"Unable to find device with id: {device_id}")
|
|
|
|
proxy: RenaultHub
|
|
for proxy in hass.data[DOMAIN].values():
|
|
for vin, vehicle in proxy.vehicles.items():
|
|
if (DOMAIN, vin) in device_entry.identifiers:
|
|
return vehicle
|
|
raise ValueError(f"Unable to find vehicle with VIN: {device_entry.identifiers}")
|
|
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_AC_CANCEL,
|
|
ac_cancel,
|
|
schema=SERVICE_VEHICLE_SCHEMA,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_AC_START,
|
|
ac_start,
|
|
schema=SERVICE_AC_START_SCHEMA,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_CHARGE_SET_SCHEDULES,
|
|
charge_set_schedules,
|
|
schema=SERVICE_CHARGE_SET_SCHEDULES_SCHEMA,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_CHARGE_START,
|
|
charge_start,
|
|
schema=SERVICE_VEHICLE_SCHEMA,
|
|
)
|
|
|
|
|
|
def unload_services(hass: HomeAssistant) -> None:
|
|
"""Unload Renault services."""
|
|
for service in SERVICES:
|
|
hass.services.async_remove(DOMAIN, service)
|