mirror of
https://github.com/home-assistant/core.git
synced 2025-09-10 15:21:38 +02:00
Add charging and preconditioning actions to Teslemetry (#144184)
This commit is contained in:
@@ -773,6 +773,18 @@
|
|||||||
},
|
},
|
||||||
"time_of_use": {
|
"time_of_use": {
|
||||||
"service": "mdi:clock-time-eight-outline"
|
"service": "mdi:clock-time-eight-outline"
|
||||||
|
},
|
||||||
|
"add_charge_schedule": {
|
||||||
|
"service": "mdi:calendar-plus"
|
||||||
|
},
|
||||||
|
"remove_charge_schedule": {
|
||||||
|
"service": "mdi:calendar-minus"
|
||||||
|
},
|
||||||
|
"add_precondition_schedule": {
|
||||||
|
"service": "mdi:hvac-outline"
|
||||||
|
},
|
||||||
|
"remove_precondition_schedule": {
|
||||||
|
"service": "mdi:hvac-off-outline"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ ATTR_ID = "id"
|
|||||||
ATTR_GPS = "gps"
|
ATTR_GPS = "gps"
|
||||||
ATTR_TYPE = "type"
|
ATTR_TYPE = "type"
|
||||||
ATTR_VALUE = "value"
|
ATTR_VALUE = "value"
|
||||||
|
ATTR_LOCATION = "location"
|
||||||
ATTR_LOCALE = "locale"
|
ATTR_LOCALE = "locale"
|
||||||
ATTR_ORDER = "order"
|
ATTR_ORDER = "order"
|
||||||
ATTR_TIMESTAMP = "timestamp"
|
ATTR_TIMESTAMP = "timestamp"
|
||||||
@@ -36,6 +37,12 @@ ATTR_DEPARTURE_TIME = "departure_time"
|
|||||||
ATTR_OFF_PEAK_CHARGING_ENABLED = "off_peak_charging_enabled"
|
ATTR_OFF_PEAK_CHARGING_ENABLED = "off_peak_charging_enabled"
|
||||||
ATTR_OFF_PEAK_CHARGING_WEEKDAYS = "off_peak_charging_weekdays_only"
|
ATTR_OFF_PEAK_CHARGING_WEEKDAYS = "off_peak_charging_weekdays_only"
|
||||||
ATTR_END_OFF_PEAK_TIME = "end_off_peak_time"
|
ATTR_END_OFF_PEAK_TIME = "end_off_peak_time"
|
||||||
|
ATTR_DAYS_OF_WEEK = "days_of_week"
|
||||||
|
ATTR_START_TIME = "start_time"
|
||||||
|
ATTR_END_TIME = "end_time"
|
||||||
|
ATTR_ONE_TIME = "one_time"
|
||||||
|
ATTR_NAME = "name"
|
||||||
|
ATTR_PRECONDITION_TIME = "precondition_time"
|
||||||
|
|
||||||
# Services
|
# Services
|
||||||
SERVICE_NAVIGATE_ATTR_GPS_REQUEST = "navigation_gps_request"
|
SERVICE_NAVIGATE_ATTR_GPS_REQUEST = "navigation_gps_request"
|
||||||
@@ -44,6 +51,10 @@ SERVICE_SET_SCHEDULED_DEPARTURE = "set_scheduled_departure"
|
|||||||
SERVICE_VALET_MODE = "valet_mode"
|
SERVICE_VALET_MODE = "valet_mode"
|
||||||
SERVICE_SPEED_LIMIT = "speed_limit"
|
SERVICE_SPEED_LIMIT = "speed_limit"
|
||||||
SERVICE_TIME_OF_USE = "time_of_use"
|
SERVICE_TIME_OF_USE = "time_of_use"
|
||||||
|
SERVICE_ADD_CHARGE_SCHEDULE = "add_charge_schedule"
|
||||||
|
SERVICE_REMOVE_CHARGE_SCHEDULE = "remove_charge_schedule"
|
||||||
|
SERVICE_ADD_PRECONDITION_SCHEDULE = "add_precondition_schedule"
|
||||||
|
SERVICE_REMOVE_PRECONDITION_SCHEDULE = "remove_precondition_schedule"
|
||||||
|
|
||||||
|
|
||||||
def async_get_device_for_service_call(
|
def async_get_device_for_service_call(
|
||||||
@@ -315,3 +326,195 @@ def async_setup_services(hass: HomeAssistant) -> None:
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def add_charge_schedule(call: ServiceCall) -> None:
|
||||||
|
"""Configure charging schedule for a vehicle."""
|
||||||
|
device = async_get_device_for_service_call(hass, call)
|
||||||
|
config = async_get_config_for_device(hass, device)
|
||||||
|
vehicle = async_get_vehicle_for_entry(hass, device, config)
|
||||||
|
|
||||||
|
# Extract parameters from the service call
|
||||||
|
days_of_week = call.data[ATTR_DAYS_OF_WEEK]
|
||||||
|
# If days_of_week is a list (from select with multiple), convert to comma-separated string
|
||||||
|
if isinstance(days_of_week, list):
|
||||||
|
days_of_week = ",".join(days_of_week)
|
||||||
|
enabled = call.data[ATTR_ENABLE]
|
||||||
|
|
||||||
|
# Optional parameters
|
||||||
|
location = call.data.get(
|
||||||
|
ATTR_LOCATION,
|
||||||
|
{
|
||||||
|
CONF_LATITUDE: hass.config.latitude,
|
||||||
|
CONF_LONGITUDE: hass.config.longitude,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Handle time inputs
|
||||||
|
start_time = None
|
||||||
|
if start_time_obj := call.data.get(ATTR_START_TIME):
|
||||||
|
# Convert time object to minutes since midnight
|
||||||
|
start_time = start_time_obj.hour * 60 + start_time_obj.minute
|
||||||
|
|
||||||
|
end_time = None
|
||||||
|
if end_time_obj := call.data.get(ATTR_END_TIME):
|
||||||
|
# Convert time object to minutes since midnight
|
||||||
|
end_time = end_time_obj.hour * 60 + end_time_obj.minute
|
||||||
|
|
||||||
|
one_time = call.data.get(ATTR_ONE_TIME)
|
||||||
|
schedule_id = call.data.get(ATTR_ID)
|
||||||
|
name = call.data.get(ATTR_NAME)
|
||||||
|
|
||||||
|
await handle_vehicle_command(
|
||||||
|
vehicle.api.add_charge_schedule(
|
||||||
|
days_of_week=days_of_week,
|
||||||
|
enabled=enabled,
|
||||||
|
lat=location[CONF_LATITUDE],
|
||||||
|
lon=location[CONF_LONGITUDE],
|
||||||
|
start_time=start_time,
|
||||||
|
end_time=end_time,
|
||||||
|
one_time=one_time,
|
||||||
|
id=schedule_id,
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_ADD_CHARGE_SCHEDULE,
|
||||||
|
add_charge_schedule,
|
||||||
|
schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_DEVICE_ID): cv.string,
|
||||||
|
vol.Required(ATTR_DAYS_OF_WEEK): cv.ensure_list,
|
||||||
|
vol.Required(ATTR_ENABLE): cv.boolean,
|
||||||
|
vol.Optional(ATTR_LOCATION): {
|
||||||
|
vol.Required(CONF_LATITUDE): cv.latitude,
|
||||||
|
vol.Required(CONF_LONGITUDE): cv.longitude,
|
||||||
|
},
|
||||||
|
vol.Optional(ATTR_START_TIME): cv.time,
|
||||||
|
vol.Optional(ATTR_END_TIME): cv.time,
|
||||||
|
vol.Optional(ATTR_ONE_TIME): cv.boolean,
|
||||||
|
vol.Optional(ATTR_ID): cv.positive_int,
|
||||||
|
vol.Optional(ATTR_NAME): cv.string,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def remove_charge_schedule(call: ServiceCall) -> None:
|
||||||
|
"""Remove a charging schedule for a vehicle."""
|
||||||
|
device = async_get_device_for_service_call(hass, call)
|
||||||
|
config = async_get_config_for_device(hass, device)
|
||||||
|
vehicle = async_get_vehicle_for_entry(hass, device, config)
|
||||||
|
|
||||||
|
# Extract parameters from the service call
|
||||||
|
schedule_id = call.data[ATTR_ID]
|
||||||
|
|
||||||
|
await handle_vehicle_command(
|
||||||
|
vehicle.api.remove_charge_schedule(
|
||||||
|
id=schedule_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_REMOVE_CHARGE_SCHEDULE,
|
||||||
|
remove_charge_schedule,
|
||||||
|
schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_DEVICE_ID): cv.string,
|
||||||
|
vol.Required(ATTR_ID): cv.positive_int,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def add_precondition_schedule(call: ServiceCall) -> None:
|
||||||
|
"""Add or modify a precondition schedule for a vehicle."""
|
||||||
|
device = async_get_device_for_service_call(hass, call)
|
||||||
|
config = async_get_config_for_device(hass, device)
|
||||||
|
vehicle = async_get_vehicle_for_entry(hass, device, config)
|
||||||
|
|
||||||
|
# Extract parameters from the service call
|
||||||
|
days_of_week = call.data[ATTR_DAYS_OF_WEEK]
|
||||||
|
# If days_of_week is a list (from select with multiple), convert to comma-separated string
|
||||||
|
if isinstance(days_of_week, list):
|
||||||
|
days_of_week = ",".join(days_of_week)
|
||||||
|
enabled = call.data[ATTR_ENABLE]
|
||||||
|
location = call.data.get(
|
||||||
|
ATTR_LOCATION,
|
||||||
|
{
|
||||||
|
CONF_LATITUDE: hass.config.latitude,
|
||||||
|
CONF_LONGITUDE: hass.config.longitude,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Convert time object to minutes since midnight
|
||||||
|
precondition_time = (
|
||||||
|
call.data[ATTR_PRECONDITION_TIME].hour * 60
|
||||||
|
+ call.data[ATTR_PRECONDITION_TIME].minute
|
||||||
|
)
|
||||||
|
|
||||||
|
# Optional parameters
|
||||||
|
schedule_id = call.data.get(ATTR_ID)
|
||||||
|
one_time = call.data.get(ATTR_ONE_TIME)
|
||||||
|
name = call.data.get(ATTR_NAME)
|
||||||
|
|
||||||
|
await handle_vehicle_command(
|
||||||
|
vehicle.api.add_precondition_schedule(
|
||||||
|
days_of_week=days_of_week,
|
||||||
|
enabled=enabled,
|
||||||
|
lat=location[CONF_LATITUDE],
|
||||||
|
lon=location[CONF_LONGITUDE],
|
||||||
|
precondition_time=precondition_time,
|
||||||
|
id=schedule_id,
|
||||||
|
one_time=one_time,
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_ADD_PRECONDITION_SCHEDULE,
|
||||||
|
add_precondition_schedule,
|
||||||
|
schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_DEVICE_ID): cv.string,
|
||||||
|
vol.Required(ATTR_DAYS_OF_WEEK): cv.ensure_list,
|
||||||
|
vol.Required(ATTR_ENABLE): cv.boolean,
|
||||||
|
vol.Optional(ATTR_LOCATION): {
|
||||||
|
vol.Required(CONF_LATITUDE): cv.latitude,
|
||||||
|
vol.Required(CONF_LONGITUDE): cv.longitude,
|
||||||
|
},
|
||||||
|
vol.Required(ATTR_PRECONDITION_TIME): cv.time,
|
||||||
|
vol.Optional(ATTR_ID): cv.positive_int,
|
||||||
|
vol.Optional(ATTR_ONE_TIME): cv.boolean,
|
||||||
|
vol.Optional(ATTR_NAME): cv.string,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def remove_precondition_schedule(call: ServiceCall) -> None:
|
||||||
|
"""Remove a preconditioning schedule for a vehicle."""
|
||||||
|
device = async_get_device_for_service_call(hass, call)
|
||||||
|
config = async_get_config_for_device(hass, device)
|
||||||
|
vehicle = async_get_vehicle_for_entry(hass, device, config)
|
||||||
|
|
||||||
|
# Extract parameters from the service call
|
||||||
|
schedule_id = call.data[ATTR_ID]
|
||||||
|
|
||||||
|
await handle_vehicle_command(
|
||||||
|
vehicle.api.remove_precondition_schedule(
|
||||||
|
id=schedule_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_REMOVE_PRECONDITION_SCHEDULE,
|
||||||
|
remove_precondition_schedule,
|
||||||
|
schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_DEVICE_ID): cv.string,
|
||||||
|
vol.Required(ATTR_ID): cv.positive_int,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@@ -130,3 +130,139 @@ speed_limit:
|
|||||||
min: 1000
|
min: 1000
|
||||||
max: 9999
|
max: 9999
|
||||||
mode: box
|
mode: box
|
||||||
|
|
||||||
|
add_charge_schedule:
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
filter:
|
||||||
|
integration: teslemetry
|
||||||
|
days_of_week:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
options:
|
||||||
|
- monday
|
||||||
|
- tuesday
|
||||||
|
- wednesday
|
||||||
|
- thursday
|
||||||
|
- friday
|
||||||
|
- saturday
|
||||||
|
- sunday
|
||||||
|
multiple: true
|
||||||
|
translation_key: days_of_week
|
||||||
|
enable:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
boolean:
|
||||||
|
location:
|
||||||
|
required: false
|
||||||
|
example: '{"latitude": -27.9699373, "longitude": 153.4081865}'
|
||||||
|
selector:
|
||||||
|
location:
|
||||||
|
radius: false
|
||||||
|
start_time:
|
||||||
|
required: false
|
||||||
|
selector:
|
||||||
|
time:
|
||||||
|
end_time:
|
||||||
|
required: false
|
||||||
|
selector:
|
||||||
|
time:
|
||||||
|
one_time:
|
||||||
|
required: false
|
||||||
|
selector:
|
||||||
|
boolean:
|
||||||
|
id:
|
||||||
|
required: false
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: 1
|
||||||
|
mode: box
|
||||||
|
name:
|
||||||
|
required: false
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
|
||||||
|
remove_charge_schedule:
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
filter:
|
||||||
|
integration: teslemetry
|
||||||
|
id:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: 1
|
||||||
|
mode: box
|
||||||
|
|
||||||
|
add_precondition_schedule:
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
filter:
|
||||||
|
integration: teslemetry
|
||||||
|
days_of_week:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
options:
|
||||||
|
- monday
|
||||||
|
- tuesday
|
||||||
|
- wednesday
|
||||||
|
- thursday
|
||||||
|
- friday
|
||||||
|
- saturday
|
||||||
|
- sunday
|
||||||
|
multiple: true
|
||||||
|
translation_key: days_of_week
|
||||||
|
enable:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
boolean:
|
||||||
|
location:
|
||||||
|
required: false
|
||||||
|
example: '{"latitude": -27.9699373, "longitude": 153.4081865}'
|
||||||
|
selector:
|
||||||
|
location:
|
||||||
|
radius: false
|
||||||
|
precondition_time:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
time:
|
||||||
|
id:
|
||||||
|
required: false
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: 1
|
||||||
|
mode: box
|
||||||
|
one_time:
|
||||||
|
required: false
|
||||||
|
selector:
|
||||||
|
boolean:
|
||||||
|
name:
|
||||||
|
required: false
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
|
||||||
|
remove_precondition_schedule:
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
filter:
|
||||||
|
integration: teslemetry
|
||||||
|
id:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: 1
|
||||||
|
mode: box
|
||||||
|
@@ -3,6 +3,26 @@
|
|||||||
"unavailable": "Unavailable",
|
"unavailable": "Unavailable",
|
||||||
"abort": "Abort",
|
"abort": "Abort",
|
||||||
"vehicle": "Vehicle",
|
"vehicle": "Vehicle",
|
||||||
|
"wake_up_failed": "Failed to wake up vehicle: {message}",
|
||||||
|
"wake_up_timeout": "Timed out trying to wake up vehicle",
|
||||||
|
"schedule_id": "Schedule ID",
|
||||||
|
"schedule_id_description": "The ID of the schedule, use an existing ID to modify.",
|
||||||
|
"days_of_week": "Days of week",
|
||||||
|
"days_of_week_description": "Select which days this schedule should be enabled on. You can select multiple days.",
|
||||||
|
"one_time": "One-time",
|
||||||
|
"one_time_description": "If this is a one-time schedule.",
|
||||||
|
"location_description": "The approximate location the vehicle must be at to use this schedule. Defaults to Home Assistant's configured location.",
|
||||||
|
"start_time": "Start time",
|
||||||
|
"start_time_description": "The time this schedule begins, e.g. 01:05 for 1:05 AM.",
|
||||||
|
"end_time": "End time",
|
||||||
|
"end_time_description": "The time this schedule ends, e.g. 01:05 for 1:05 AM.",
|
||||||
|
"precondition_time": "Precondition time",
|
||||||
|
"precondition_time_description": "The time the vehicle should complete preconditioning, e.g. 01:05 for 1:05 AM.",
|
||||||
|
"schedule_name_description": "The name of the schedule.",
|
||||||
|
"vehicle_to_schedule": "Vehicle to schedule.",
|
||||||
|
"vehicle_to_remove_schedule": "Vehicle to remove schedule from.",
|
||||||
|
"schedule_enable_description": "If this schedule should be considered for execution.",
|
||||||
|
"schedule_id_remove_description": "The ID of the schedule to remove.",
|
||||||
"descr_pin": "4-digit code to enable or disable the setting"
|
"descr_pin": "4-digit code to enable or disable the setting"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
@@ -1079,15 +1099,6 @@
|
|||||||
"invalid_cop_temp": {
|
"invalid_cop_temp": {
|
||||||
"message": "Cabin overheat protection does not support that temperature"
|
"message": "Cabin overheat protection does not support that temperature"
|
||||||
},
|
},
|
||||||
"set_scheduled_charging_time": {
|
|
||||||
"message": "Time required to complete the operation"
|
|
||||||
},
|
|
||||||
"set_scheduled_departure_preconditioning": {
|
|
||||||
"message": "Departure time required to enable preconditioning"
|
|
||||||
},
|
|
||||||
"set_scheduled_departure_off_peak": {
|
|
||||||
"message": "To enable scheduled departure, 'End off-peak time' is required."
|
|
||||||
},
|
|
||||||
"invalid_device": {
|
"invalid_device": {
|
||||||
"message": "Invalid device ID: {device_id}"
|
"message": "Invalid device ID: {device_id}"
|
||||||
},
|
},
|
||||||
@@ -1145,7 +1156,7 @@
|
|||||||
"description": "Sets a time at which charging should be started.",
|
"description": "Sets a time at which charging should be started.",
|
||||||
"fields": {
|
"fields": {
|
||||||
"device_id": {
|
"device_id": {
|
||||||
"description": "Vehicle to schedule.",
|
"description": "[%key:component::teslemetry::common::vehicle_to_schedule%]",
|
||||||
"name": "[%key:component::teslemetry::common::vehicle%]"
|
"name": "[%key:component::teslemetry::common::vehicle%]"
|
||||||
},
|
},
|
||||||
"enable": {
|
"enable": {
|
||||||
@@ -1167,7 +1178,7 @@
|
|||||||
"name": "Departure time"
|
"name": "Departure time"
|
||||||
},
|
},
|
||||||
"device_id": {
|
"device_id": {
|
||||||
"description": "Vehicle to schedule.",
|
"description": "[%key:component::teslemetry::common::vehicle_to_schedule%]",
|
||||||
"name": "[%key:component::teslemetry::common::vehicle%]"
|
"name": "[%key:component::teslemetry::common::vehicle%]"
|
||||||
},
|
},
|
||||||
"enable": {
|
"enable": {
|
||||||
@@ -1246,6 +1257,127 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "Set valet mode"
|
"name": "Set valet mode"
|
||||||
|
},
|
||||||
|
"add_charge_schedule": {
|
||||||
|
"description": "Adds or modifies a charging schedule for a vehicle.",
|
||||||
|
"fields": {
|
||||||
|
"device_id": {
|
||||||
|
"description": "[%key:component::teslemetry::common::vehicle_to_schedule%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::vehicle%]"
|
||||||
|
},
|
||||||
|
"days_of_week": {
|
||||||
|
"description": "[%key:component::teslemetry::common::days_of_week_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::days_of_week%]"
|
||||||
|
},
|
||||||
|
"enable": {
|
||||||
|
"description": "[%key:component::teslemetry::common::schedule_enable_description%]",
|
||||||
|
"name": "[%key:common::action::enable%]"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"description": "[%key:component::teslemetry::common::location_description%]",
|
||||||
|
"name": "Location"
|
||||||
|
},
|
||||||
|
"start_time": {
|
||||||
|
"description": "[%key:component::teslemetry::common::start_time_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::start_time%]"
|
||||||
|
},
|
||||||
|
"end_time": {
|
||||||
|
"description": "[%key:component::teslemetry::common::end_time_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::end_time%]"
|
||||||
|
},
|
||||||
|
"one_time": {
|
||||||
|
"description": "[%key:component::teslemetry::common::one_time_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::one_time%]"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "[%key:component::teslemetry::common::schedule_id_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::schedule_id%]"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"description": "[%key:component::teslemetry::common::schedule_name_description%]",
|
||||||
|
"name": "[%key:common::config_flow::data::name%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Add charge schedule"
|
||||||
|
},
|
||||||
|
"remove_charge_schedule": {
|
||||||
|
"description": "Removes a charging schedule for a vehicle.",
|
||||||
|
"fields": {
|
||||||
|
"device_id": {
|
||||||
|
"description": "[%key:component::teslemetry::common::vehicle_to_remove_schedule%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::vehicle%]"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "[%key:component::teslemetry::common::schedule_id_remove_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::schedule_id%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Remove charge schedule"
|
||||||
|
},
|
||||||
|
"add_precondition_schedule": {
|
||||||
|
"description": "Adds or modifies a preconditioning schedule for a vehicle.",
|
||||||
|
"fields": {
|
||||||
|
"device_id": {
|
||||||
|
"description": "[%key:component::teslemetry::common::vehicle_to_schedule%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::vehicle%]"
|
||||||
|
},
|
||||||
|
"days_of_week": {
|
||||||
|
"description": "[%key:component::teslemetry::common::days_of_week_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::days_of_week%]"
|
||||||
|
},
|
||||||
|
"enable": {
|
||||||
|
"description": "[%key:component::teslemetry::common::schedule_enable_description%]",
|
||||||
|
"name": "[%key:common::action::enable%]"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"description": "[%key:component::teslemetry::common::location_description%]",
|
||||||
|
"name": "Location"
|
||||||
|
},
|
||||||
|
"precondition_time": {
|
||||||
|
"description": "[%key:component::teslemetry::common::precondition_time_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::precondition_time%]"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "[%key:component::teslemetry::common::schedule_id_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::schedule_id%]"
|
||||||
|
},
|
||||||
|
"one_time": {
|
||||||
|
"description": "[%key:component::teslemetry::common::one_time_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::one_time%]"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"description": "[%key:component::teslemetry::common::schedule_name_description%]",
|
||||||
|
"name": "[%key:common::config_flow::data::name%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Add precondition schedule"
|
||||||
|
},
|
||||||
|
"remove_precondition_schedule": {
|
||||||
|
"description": "Removes a preconditioning schedule for a vehicle.",
|
||||||
|
"fields": {
|
||||||
|
"device_id": {
|
||||||
|
"description": "[%key:component::teslemetry::common::vehicle_to_remove_schedule%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::vehicle%]"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "[%key:component::teslemetry::common::schedule_id_remove_description%]",
|
||||||
|
"name": "[%key:component::teslemetry::common::schedule_id%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Remove precondition schedule"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"selector": {
|
||||||
|
"days_of_week": {
|
||||||
|
"options": {
|
||||||
|
"monday": "[%key:common::time::monday%]",
|
||||||
|
"tuesday": "[%key:common::time::tuesday%]",
|
||||||
|
"wednesday": "[%key:common::time::wednesday%]",
|
||||||
|
"thursday": "[%key:common::time::thursday%]",
|
||||||
|
"friday": "[%key:common::time::friday%]",
|
||||||
|
"saturday": "[%key:common::time::saturday%]",
|
||||||
|
"sunday": "[%key:common::time::sunday%]"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,23 +1,36 @@
|
|||||||
"""Test the Teslemetry services."""
|
"""Test the Teslemetry services."""
|
||||||
|
|
||||||
|
from datetime import time
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.teslemetry.const import DOMAIN
|
from homeassistant.components.teslemetry.const import DOMAIN
|
||||||
from homeassistant.components.teslemetry.services import (
|
from homeassistant.components.teslemetry.services import (
|
||||||
|
ATTR_DAYS_OF_WEEK,
|
||||||
ATTR_DEPARTURE_TIME,
|
ATTR_DEPARTURE_TIME,
|
||||||
ATTR_ENABLE,
|
ATTR_ENABLE,
|
||||||
ATTR_END_OFF_PEAK_TIME,
|
ATTR_END_OFF_PEAK_TIME,
|
||||||
|
ATTR_END_TIME,
|
||||||
ATTR_GPS,
|
ATTR_GPS,
|
||||||
|
ATTR_ID,
|
||||||
|
ATTR_LOCATION,
|
||||||
|
ATTR_NAME,
|
||||||
ATTR_OFF_PEAK_CHARGING_ENABLED,
|
ATTR_OFF_PEAK_CHARGING_ENABLED,
|
||||||
ATTR_OFF_PEAK_CHARGING_WEEKDAYS,
|
ATTR_OFF_PEAK_CHARGING_WEEKDAYS,
|
||||||
|
ATTR_ONE_TIME,
|
||||||
ATTR_PIN,
|
ATTR_PIN,
|
||||||
|
ATTR_PRECONDITION_TIME,
|
||||||
ATTR_PRECONDITIONING_ENABLED,
|
ATTR_PRECONDITIONING_ENABLED,
|
||||||
ATTR_PRECONDITIONING_WEEKDAYS,
|
ATTR_PRECONDITIONING_WEEKDAYS,
|
||||||
|
ATTR_START_TIME,
|
||||||
ATTR_TIME,
|
ATTR_TIME,
|
||||||
ATTR_TOU_SETTINGS,
|
ATTR_TOU_SETTINGS,
|
||||||
|
SERVICE_ADD_CHARGE_SCHEDULE,
|
||||||
|
SERVICE_ADD_PRECONDITION_SCHEDULE,
|
||||||
SERVICE_NAVIGATE_ATTR_GPS_REQUEST,
|
SERVICE_NAVIGATE_ATTR_GPS_REQUEST,
|
||||||
|
SERVICE_REMOVE_CHARGE_SCHEDULE,
|
||||||
|
SERVICE_REMOVE_PRECONDITION_SCHEDULE,
|
||||||
SERVICE_SET_SCHEDULED_CHARGING,
|
SERVICE_SET_SCHEDULED_CHARGING,
|
||||||
SERVICE_SET_SCHEDULED_DEPARTURE,
|
SERVICE_SET_SCHEDULED_DEPARTURE,
|
||||||
SERVICE_SPEED_LIMIT,
|
SERVICE_SPEED_LIMIT,
|
||||||
@@ -75,23 +88,12 @@ async def test_services(
|
|||||||
{
|
{
|
||||||
CONF_DEVICE_ID: vehicle_device,
|
CONF_DEVICE_ID: vehicle_device,
|
||||||
ATTR_ENABLE: True,
|
ATTR_ENABLE: True,
|
||||||
ATTR_TIME: "6:00",
|
ATTR_TIME: "06:00", # 6:00 AM
|
||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
set_scheduled_charging.assert_called_once()
|
set_scheduled_charging.assert_called_once()
|
||||||
|
|
||||||
with pytest.raises(ServiceValidationError):
|
|
||||||
await hass.services.async_call(
|
|
||||||
DOMAIN,
|
|
||||||
SERVICE_SET_SCHEDULED_CHARGING,
|
|
||||||
{
|
|
||||||
CONF_DEVICE_ID: vehicle_device,
|
|
||||||
ATTR_ENABLE: True,
|
|
||||||
},
|
|
||||||
blocking=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"tesla_fleet_api.teslemetry.Vehicle.set_scheduled_departure",
|
"tesla_fleet_api.teslemetry.Vehicle.set_scheduled_departure",
|
||||||
return_value=COMMAND_OK,
|
return_value=COMMAND_OK,
|
||||||
@@ -104,39 +106,15 @@ async def test_services(
|
|||||||
ATTR_ENABLE: True,
|
ATTR_ENABLE: True,
|
||||||
ATTR_PRECONDITIONING_ENABLED: True,
|
ATTR_PRECONDITIONING_ENABLED: True,
|
||||||
ATTR_PRECONDITIONING_WEEKDAYS: False,
|
ATTR_PRECONDITIONING_WEEKDAYS: False,
|
||||||
ATTR_DEPARTURE_TIME: "6:00",
|
ATTR_DEPARTURE_TIME: "06:00", # 6:00 AM
|
||||||
ATTR_OFF_PEAK_CHARGING_ENABLED: True,
|
ATTR_OFF_PEAK_CHARGING_ENABLED: True,
|
||||||
ATTR_OFF_PEAK_CHARGING_WEEKDAYS: False,
|
ATTR_OFF_PEAK_CHARGING_WEEKDAYS: False,
|
||||||
ATTR_END_OFF_PEAK_TIME: "5:00",
|
ATTR_END_OFF_PEAK_TIME: "05:00", # 5:00 AM
|
||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
set_scheduled_departure.assert_called_once()
|
set_scheduled_departure.assert_called_once()
|
||||||
|
|
||||||
with pytest.raises(ServiceValidationError):
|
|
||||||
await hass.services.async_call(
|
|
||||||
DOMAIN,
|
|
||||||
SERVICE_SET_SCHEDULED_DEPARTURE,
|
|
||||||
{
|
|
||||||
CONF_DEVICE_ID: vehicle_device,
|
|
||||||
ATTR_ENABLE: True,
|
|
||||||
ATTR_PRECONDITIONING_ENABLED: True,
|
|
||||||
},
|
|
||||||
blocking=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
with pytest.raises(ServiceValidationError):
|
|
||||||
await hass.services.async_call(
|
|
||||||
DOMAIN,
|
|
||||||
SERVICE_SET_SCHEDULED_DEPARTURE,
|
|
||||||
{
|
|
||||||
CONF_DEVICE_ID: vehicle_device,
|
|
||||||
ATTR_ENABLE: True,
|
|
||||||
ATTR_OFF_PEAK_CHARGING_ENABLED: True,
|
|
||||||
},
|
|
||||||
blocking=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"tesla_fleet_api.teslemetry.Vehicle.set_valet_mode",
|
"tesla_fleet_api.teslemetry.Vehicle.set_valet_mode",
|
||||||
return_value=COMMAND_OK,
|
return_value=COMMAND_OK,
|
||||||
@@ -200,6 +178,112 @@ async def test_services(
|
|||||||
)
|
)
|
||||||
set_time_of_use.assert_called_once()
|
set_time_of_use.assert_called_once()
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"tesla_fleet_api.teslemetry.Vehicle.add_charge_schedule",
|
||||||
|
return_value=COMMAND_OK,
|
||||||
|
) as add_charge_schedule:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_ADD_CHARGE_SCHEDULE,
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: vehicle_device,
|
||||||
|
ATTR_DAYS_OF_WEEK: ["Monday", "Tuesday"],
|
||||||
|
ATTR_ENABLE: True,
|
||||||
|
ATTR_LOCATION: {CONF_LATITUDE: lat, CONF_LONGITUDE: lon},
|
||||||
|
ATTR_START_TIME: time(7, 0, 0), # 7:00 AM
|
||||||
|
ATTR_END_TIME: time(18, 0, 0), # 6:00 PM
|
||||||
|
ATTR_ONE_TIME: False,
|
||||||
|
ATTR_NAME: "Test Schedule",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
add_charge_schedule.assert_called_once()
|
||||||
|
|
||||||
|
# Test add_charge_schedule with minimal required parameters
|
||||||
|
with patch(
|
||||||
|
"tesla_fleet_api.teslemetry.Vehicle.add_charge_schedule",
|
||||||
|
return_value=COMMAND_OK,
|
||||||
|
) as add_charge_schedule_minimal:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_ADD_CHARGE_SCHEDULE,
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: vehicle_device,
|
||||||
|
ATTR_DAYS_OF_WEEK: ["Monday", "Tuesday"],
|
||||||
|
ATTR_ENABLE: True,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
add_charge_schedule_minimal.assert_called_once()
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"tesla_fleet_api.teslemetry.Vehicle.remove_charge_schedule",
|
||||||
|
return_value=COMMAND_OK,
|
||||||
|
) as remove_charge_schedule:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_REMOVE_CHARGE_SCHEDULE,
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: vehicle_device,
|
||||||
|
ATTR_ID: 123,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
remove_charge_schedule.assert_called_once()
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"tesla_fleet_api.teslemetry.Vehicle.add_precondition_schedule",
|
||||||
|
return_value=COMMAND_OK,
|
||||||
|
) as add_precondition_schedule:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_ADD_PRECONDITION_SCHEDULE,
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: vehicle_device,
|
||||||
|
ATTR_DAYS_OF_WEEK: ["Monday", "Tuesday"],
|
||||||
|
ATTR_ENABLE: True,
|
||||||
|
ATTR_LOCATION: {CONF_LATITUDE: lat, CONF_LONGITUDE: lon},
|
||||||
|
ATTR_PRECONDITION_TIME: time(7, 0, 0), # 7:00 AM
|
||||||
|
ATTR_ONE_TIME: False,
|
||||||
|
ATTR_NAME: "Test Precondition Schedule",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
add_precondition_schedule.assert_called_once()
|
||||||
|
|
||||||
|
# Test add_precondition_schedule with minimal required parameters
|
||||||
|
with patch(
|
||||||
|
"tesla_fleet_api.teslemetry.Vehicle.add_precondition_schedule",
|
||||||
|
return_value=COMMAND_OK,
|
||||||
|
) as add_precondition_schedule_minimal:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_ADD_PRECONDITION_SCHEDULE,
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: vehicle_device,
|
||||||
|
ATTR_DAYS_OF_WEEK: ["Monday", "Tuesday"],
|
||||||
|
ATTR_ENABLE: True,
|
||||||
|
ATTR_PRECONDITION_TIME: time(8, 0, 0), # 8:00 AM
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
add_precondition_schedule_minimal.assert_called_once()
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"tesla_fleet_api.teslemetry.Vehicle.remove_precondition_schedule",
|
||||||
|
return_value=COMMAND_OK,
|
||||||
|
) as remove_precondition_schedule:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_REMOVE_PRECONDITION_SCHEDULE,
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: vehicle_device,
|
||||||
|
ATTR_ID: 123,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
remove_precondition_schedule.assert_called_once()
|
||||||
|
|
||||||
with (
|
with (
|
||||||
patch(
|
patch(
|
||||||
"tesla_fleet_api.teslemetry.EnergySite.time_of_use_settings",
|
"tesla_fleet_api.teslemetry.EnergySite.time_of_use_settings",
|
||||||
|
Reference in New Issue
Block a user