text: """Support for Renault services."""
  import logging
  from typing import Any, Dict
  
  from renault_api.kamereon.exceptions import KamereonResponseException
  import voluptuous as vol
  
  from homeassistant.helpers import config_validation as cv
  from homeassistant.helpers.typing import HomeAssistantType
  
  from .const import DOMAIN, REGEX_VIN
  from .renault_hub import RenaultHub
  from .renault_vehicle import RenaultVehicleProxy
  
  _LOGGER = logging.getLogger(__name__)
  
  RENAULT_SERVICES = "renault_services"
  
  SCHEMA_CHARGE_MODE = "charge_mode"
  SCHEMA_SCHEDULES = "schedules"
  SCHEMA_TEMPERATURE = "temperature"
  SCHEMA_VIN = "vin"
  SCHEMA_WHEN = "when"
  
  SERVICE_AC_CANCEL = "ac_cancel"
  SERVICE_AC_CANCEL_SCHEMA = vol.Schema(
      {
          vol.Required(SCHEMA_VIN): cv.matches_regex(REGEX_VIN),
      }
  )
  SERVICE_AC_START = "ac_start"
  SERVICE_AC_START_SCHEMA = vol.Schema(
      {
          vol.Required(SCHEMA_VIN): cv.matches_regex(REGEX_VIN),
          vol.Optional(SCHEMA_WHEN): cv.datetime,
          vol.Optional(SCHEMA_TEMPERATURE): cv.positive_int,
      }
  )
  SERVICE_CHARGE_SET_MODE = "charge_set_mode"
  SERVICE_CHARGE_SET_MODE_SCHEMA = vol.Schema(
      {
          vol.Required(SCHEMA_VIN): cv.matches_regex(REGEX_VIN),
          vol.Required(SCHEMA_CHARGE_MODE): cv.string,
      }
  )
  SERVICE_CHARGE_SET_SCHEDULES = "charge_set_schedules"
  SERVICE_CHARGE_SET_SCHEDULES_SCHEMA = vol.Schema(
      {
          vol.Required(SCHEMA_VIN): cv.matches_regex(REGEX_VIN),
          vol.Required(SCHEMA_SCHEDULES): dict,
      }
  )
  SERVICE_CHARGE_START = "charge_start"
  SERVICE_CHARGE_START_SCHEMA = vol.Schema(
      {
          vol.Required(SCHEMA_VIN): cv.matches_regex(REGEX_VIN),
      }
  )
  
  
  async def async_setup_services(hass: HomeAssistantType) -> None:
      """Register the Renault services."""
      _LOGGER.debug("Registering renault services")
  
      if hass.data.get(RENAULT_SERVICES, False):
          return
  
      hass.data[RENAULT_SERVICES] = True
  
      async def ac_start(service_call) -> None:
          """Start A/C."""
          service_call_data: Dict[str, Any] = service_call.data
          when = service_call_data.get(SCHEMA_WHEN, None)
          temperature = service_call_data.get(SCHEMA_TEMPERATURE, 21)
          vehicle = get_vehicle(service_call_data)
          _LOGGER.debug("A/C start attempt: %s / %s", when, temperature)
          try:
              result = await vehicle.send_ac_start(temperature=temperature, when=when)
          except KamereonResponseException as err:
              _LOGGER.error("A/C start failed: %s", err)
          else:
              _LOGGER.info("A/C start result: %s", result.raw_data)
  
      async def ac_cancel(service_call) -> None:
          """Cancel A/C."""
          service_call_data: Dict[str, Any] = service_call.data
          vehicle = get_vehicle(service_call_data)
          _LOGGER.debug("A/C cancel attempt.")
          try:
              result = await vehicle.send_cancel_ac()
          except KamereonResponseException as err:
              _LOGGER.error("A/C cancel failed: %s", err)
          else:
              _LOGGER.info("A/C cancel result: %s", result)
  
      async def charge_set_mode(service_call) -> None:
          """Set charge mode."""
          service_call_data: Dict[str, Any] = service_call.data
          charge_mode: str = service_call_data[SCHEMA_CHARGE_MODE]
          vehicle = get_vehicle(service_call_data)
          _LOGGER.debug("Charge set mode attempt: %s", charge_mode)
          try:
              # there was some confusion in earlier release regarding upper or lower case of charge-mode
              # so forcing to lower manually for the custom-component (always or always_charging or schedule_mode)
              result = await vehicle.send_set_charge_mode(charge_mode.lower())
          except KamereonResponseException as err:
              _LOGGER.error("Charge set mode failed: %s", err)
          else:
              _LOGGER.info("Charge set mode result: %s", result)
  
      async def charge_start(service_call) -> None:
          """Start charge."""
          service_call_data: Dict[str, Any] = service_call.data
          vehicle = get_vehicle(service_call_data)
          _LOGGER.debug("Charge start attempt.")
          try:
              result = await vehicle.send_charge_start()
          except KamereonResponseException as err:
              _LOGGER.error("Charge start failed: %s", err)
          else:
              _LOGGER.info("Charge start result: %s", result)
  
      async def charge_set_schedules(service_call) -> None:
          """Set charge schedules."""
          service_call_data: Dict[str, Any] = service_call.data
          schedules = service_call_data.get(SCHEMA_SCHEDULES)
          vehicle = get_vehicle(service_call_data)
          charge_schedules = await vehicle.get_charging_settings()
          charge_schedules.update(schedules)
          try:
              _LOGGER.debug("Charge set schedules attempt: %s", schedules)
              result = await vehicle.send_set_charge_schedules(charge_schedules)
          except KamereonResponseException as err:
              _LOGGER.error("Charge set schedules failed: %s", err)
          else:
              _LOGGER.info("Charge set schedules result: %s", result)
              _LOGGER.info(
                  "It may take some time before these changes are reflected in your vehicle."
              )
  
      def get_vehicle(service_call_data: Dict[str, Any]) -> RenaultVehicleProxy:
          """Get vehicle from service_call data."""
          vin: str = service_call_data[SCHEMA_VIN]
          proxy: RenaultHub
          for proxy in hass.data[DOMAIN].values():
              # there was some confusion in earlier release regarding upper or lower case of vin
              # so forcing to upper manually for the custom-component
              vehicle = proxy.vehicles.get(vin.upper())
              if vehicle is not None:
                  return vehicle
          raise ValueError(f"Unable to find vehicle with VIN: {vin}")
  
      hass.services.async_register(
          DOMAIN,
          SERVICE_AC_START,
          ac_start,
          schema=SERVICE_AC_START_SCHEMA,
      )
      hass.services.async_register(
          DOMAIN,
          SERVICE_AC_CANCEL,
          ac_cancel,
          schema=SERVICE_AC_CANCEL_SCHEMA,
      )
      hass.services.async_register(
          DOMAIN,
          SERVICE_CHARGE_START,
          charge_start,
          schema=SERVICE_CHARGE_START_SCHEMA,
      )
      hass.services.async_register(
          DOMAIN,
          SERVICE_CHARGE_SET_MODE,
          charge_set_mode,
          schema=SERVICE_CHARGE_SET_MODE_SCHEMA,
      )
      hass.services.async_register(
          DOMAIN,
          SERVICE_CHARGE_SET_SCHEDULES,
          charge_set_schedules,
          schema=SERVICE_CHARGE_SET_SCHEDULES_SCHEMA,
      )
  
  
  async def async_unload_services(hass: HomeAssistantType) -> None:
      """Unload Renault services."""
      if not hass.data.get(RENAULT_SERVICES):
          return
  
      hass.data[RENAULT_SERVICES] = False
  
      hass.services.async_remove(DOMAIN, SERVICE_AC_CANCEL)
      hass.services.async_remove(DOMAIN, SERVICE_AC_START)
      hass.services.async_remove(DOMAIN, SERVICE_CHARGE_SET_MODE)
      hass.services.async_remove(DOMAIN, SERVICE_CHARGE_SET_SCHEDULES)
      hass.services.async_remove(DOMAIN, SERVICE_CHARGE_START)
  