348 files
This commit is contained in:
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from functools import wraps
|
||||
from pathlib import Path
|
||||
|
||||
@@ -14,6 +15,7 @@ from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.exceptions import ServiceValidationError, Unauthorized
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.service import async_set_service_schema
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import (
|
||||
ATTR_AS_PARENT,
|
||||
@@ -39,12 +41,14 @@ from .const import (
|
||||
ATTR_CHILD_ID,
|
||||
ATTR_CHORE_ASSIGNED_TO,
|
||||
ATTR_CHORE_DESCRIPTION,
|
||||
ATTR_CHORE_EXPIRES_IN_MINUTES,
|
||||
ATTR_CHORE_ID,
|
||||
ATTR_CHORE_NAME,
|
||||
ATTR_CHORE_ONE_SHOT,
|
||||
ATTR_CHORE_ORDER,
|
||||
ATTR_CHORE_POINTS,
|
||||
ATTR_CHORE_REQUIRES_APPROVAL,
|
||||
ATTR_CHORE_SPEED_BONUS_POINTS,
|
||||
ATTR_CHORE_TIME_CATEGORY,
|
||||
ATTR_PENALTY_ASSIGNED_TO,
|
||||
ATTR_PENALTY_DESCRIPTION,
|
||||
@@ -85,6 +89,7 @@ from .const import (
|
||||
SERVICE_PAUSE_TIMED_TASK,
|
||||
SERVICE_POSTPONE_MANDATORY_CHORE,
|
||||
SERVICE_PREVIEW_SOUND,
|
||||
SERVICE_READ_ALOUD,
|
||||
SERVICE_RECORD_ALLOWANCE_PAYOUT,
|
||||
SERVICE_REJECT_CHORE,
|
||||
SERVICE_REJECT_REWARD,
|
||||
@@ -96,6 +101,7 @@ from .const import (
|
||||
SERVICE_SET_CHORE_MANUAL_START,
|
||||
SERVICE_SET_CHORE_ORDER,
|
||||
SERVICE_SKIP_CHORE,
|
||||
SERVICE_SPIN_ROULETTE,
|
||||
SERVICE_START_TIMED_TASK,
|
||||
SERVICE_STOP_TIMED_TASK,
|
||||
SERVICE_TEST_NOTIFICATION,
|
||||
@@ -619,6 +625,37 @@ async def _async_register_services(hass: HomeAssistant) -> None:
|
||||
await _async_require_linked_child(hass, call, coordinator, requester_id)
|
||||
await coordinator.async_request_swap(call.data["chore_id"], requester_id)
|
||||
|
||||
async def handle_read_aloud(call: ServiceCall) -> None:
|
||||
"""Speak a child's outstanding chores to a media player (#684)."""
|
||||
coordinator = _get_coordinator(hass)
|
||||
if not coordinator:
|
||||
_LOGGER.error("No TaskMate coordinator available")
|
||||
return
|
||||
try:
|
||||
await coordinator.async_read_aloud(
|
||||
child_id=call.data[ATTR_CHILD_ID],
|
||||
media_player=call.data.get("media_player", ""),
|
||||
tts_entity=call.data.get("tts_entity", ""),
|
||||
message=call.data.get("message", ""),
|
||||
)
|
||||
except ValueError as err:
|
||||
raise ServiceValidationError(str(err)) from err
|
||||
|
||||
async def handle_spin_roulette(call: ServiceCall) -> None:
|
||||
"""A child spins for a random chore at a multiplier (#677)."""
|
||||
coordinator = _get_coordinator(hass)
|
||||
if not coordinator:
|
||||
_LOGGER.error("No TaskMate coordinator available")
|
||||
return
|
||||
child_id = call.data[ATTR_CHILD_ID]
|
||||
await _async_require_linked_child(hass, call, coordinator, child_id)
|
||||
try:
|
||||
await coordinator.async_spin_roulette(child_id)
|
||||
except ValueError as err:
|
||||
# Roulette off, no spins left, nothing to spin for — all normal
|
||||
# states the child should be told about, not server errors.
|
||||
raise ServiceValidationError(str(err)) from err
|
||||
|
||||
async def handle_choose_avatar(call: ServiceCall) -> None:
|
||||
"""A child switches to an avatar they've unlocked."""
|
||||
coordinator = _get_coordinator(hass)
|
||||
@@ -882,7 +919,14 @@ async def _async_register_services(hass: HomeAssistant) -> None:
|
||||
if not coordinator:
|
||||
_LOGGER.error("No TaskMate coordinator available")
|
||||
return
|
||||
schedule_mode = "one_shot" if call.data.get(ATTR_CHORE_ONE_SHOT, False) else "specific_days"
|
||||
expires_in = call.data.get(ATTR_CHORE_EXPIRES_IN_MINUTES, 0) or 0
|
||||
# A chore with a deadline is inherently a one-off — it exists to be done
|
||||
# now, so it should never linger into tomorrow.
|
||||
one_shot = call.data.get(ATTR_CHORE_ONE_SHOT, False) or bool(expires_in)
|
||||
schedule_mode = "one_shot" if one_shot else "specific_days"
|
||||
deadline_at = ""
|
||||
if expires_in:
|
||||
deadline_at = (dt_util.now() + timedelta(minutes=expires_in)).isoformat()
|
||||
await coordinator.async_add_chore(
|
||||
name=call.data[ATTR_CHORE_NAME],
|
||||
description=call.data.get(ATTR_CHORE_DESCRIPTION, ""),
|
||||
@@ -892,6 +936,8 @@ async def _async_register_services(hass: HomeAssistant) -> None:
|
||||
requires_approval=call.data.get(ATTR_CHORE_REQUIRES_APPROVAL, True),
|
||||
difficulty=call.data.get("difficulty", "medium"),
|
||||
schedule_mode=schedule_mode,
|
||||
deadline_at=deadline_at,
|
||||
speed_bonus_points=call.data.get(ATTR_CHORE_SPEED_BONUS_POINTS, 0),
|
||||
)
|
||||
|
||||
async def handle_add_badge(call: ServiceCall) -> None:
|
||||
@@ -1188,6 +1234,25 @@ async def _async_register_services(hass: HomeAssistant) -> None:
|
||||
),
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_READ_ALOUD,
|
||||
_safe(handle_read_aloud),
|
||||
schema=vol.Schema({
|
||||
vol.Required(ATTR_CHILD_ID): cv.string,
|
||||
vol.Optional("media_player", default=""): cv.string,
|
||||
vol.Optional("tts_entity", default=""): cv.string,
|
||||
vol.Optional("message", default=""): cv.string,
|
||||
}),
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_SPIN_ROULETTE,
|
||||
_safe(handle_spin_roulette),
|
||||
schema=vol.Schema({vol.Required(ATTR_CHILD_ID): cv.string}),
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_CHOOSE_AVATAR,
|
||||
@@ -1398,6 +1463,10 @@ async def _async_register_services(hass: HomeAssistant) -> None:
|
||||
vol.Optional("difficulty", default=DEFAULT_DIFFICULTY): vol.In(DIFFICULTY_TIERS),
|
||||
vol.Optional(ATTR_CHORE_ONE_SHOT, default=False): cv.boolean,
|
||||
vol.Optional(ATTR_CHORE_REQUIRES_APPROVAL, default=True): cv.boolean,
|
||||
vol.Optional(ATTR_CHORE_EXPIRES_IN_MINUTES, default=0): vol.All(
|
||||
cv.positive_int, vol.Range(max=10080)
|
||||
),
|
||||
vol.Optional(ATTR_CHORE_SPEED_BONUS_POINTS, default=0): cv.positive_int,
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user