diff --git a/.coveragerc b/.coveragerc index a3c6737a722..cf2210ec1a0 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1615,6 +1615,7 @@ omit = homeassistant/components/yolink/lock.py homeassistant/components/yolink/number.py homeassistant/components/yolink/sensor.py + homeassistant/components/yolink/services.py homeassistant/components/yolink/siren.py homeassistant/components/yolink/switch.py homeassistant/components/youless/__init__.py diff --git a/homeassistant/components/yolink/__init__.py b/homeassistant/components/yolink/__init__.py index 16094816f17..473c85d563a 100644 --- a/homeassistant/components/yolink/__init__.py +++ b/homeassistant/components/yolink/__init__.py @@ -26,6 +26,7 @@ from . import api from .const import DOMAIN, YOLINK_EVENT from .coordinator import YoLinkCoordinator from .device_trigger import CONF_LONG_PRESS, CONF_SHORT_PRESS +from .services import async_register_services SCAN_INTERVAL = timedelta(minutes=5) @@ -146,6 +147,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + async_register_services(hass, entry) + async def async_yolink_unload(event) -> None: """Unload yolink.""" await yolink_home.async_unload() diff --git a/homeassistant/components/yolink/const.py b/homeassistant/components/yolink/const.py index 9fc4dac8ada..3d341c8b4fb 100644 --- a/homeassistant/components/yolink/const.py +++ b/homeassistant/components/yolink/const.py @@ -7,5 +7,10 @@ ATTR_DEVICE_TYPE = "type" ATTR_DEVICE_NAME = "name" ATTR_DEVICE_STATE = "state" ATTR_DEVICE_ID = "deviceId" +ATTR_TARGET_DEVICE = "target_device" +ATTR_VOLUME = "volume" +ATTR_TEXT_MESSAGE = "message" +ATTR_REPEAT = "repeat" +ATTR_TONE = "tone" YOLINK_EVENT = f"{DOMAIN}_event" YOLINK_OFFLINE_TIME = 32400 diff --git a/homeassistant/components/yolink/services.py b/homeassistant/components/yolink/services.py new file mode 100644 index 00000000000..bb2c660ef56 --- /dev/null +++ b/homeassistant/components/yolink/services.py @@ -0,0 +1,67 @@ +"""YoLink services.""" + +import voluptuous as vol +from yolink.client_request import ClientRequest + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, ServiceCall +from homeassistant.helpers import config_validation as cv, device_registry as dr + +from .const import ( + ATTR_REPEAT, + ATTR_TARGET_DEVICE, + ATTR_TEXT_MESSAGE, + ATTR_TONE, + ATTR_VOLUME, + DOMAIN, +) + +SERVICE_PLAY_ON_SPEAKER_HUB = "play_on_speaker_hub" + + +def async_register_services(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Register services for YoLink integration.""" + + async def handle_speaker_hub_play_call(service_call: ServiceCall) -> None: + """Handle Speaker Hub audio play call.""" + service_data = service_call.data + device_registry = dr.async_get(hass) + device_entry = device_registry.async_get(service_data[ATTR_TARGET_DEVICE]) + if device_entry is not None: + home_store = hass.data[DOMAIN][entry.entry_id] + for identifier in device_entry.identifiers: + if ( + device_coordinator := home_store.device_coordinators.get( + identifier[1] + ) + ) is not None: + tone_param = service_data[ATTR_TONE].capitalize() + play_request = ClientRequest( + "playAudio", + { + ATTR_TONE: tone_param, + ATTR_TEXT_MESSAGE: service_data[ATTR_TEXT_MESSAGE], + ATTR_VOLUME: service_data[ATTR_VOLUME], + ATTR_REPEAT: service_data[ATTR_REPEAT], + }, + ) + await device_coordinator.device.call_device(play_request) + + hass.services.async_register( + domain=DOMAIN, + service=SERVICE_PLAY_ON_SPEAKER_HUB, + schema=vol.Schema( + { + vol.Required(ATTR_TARGET_DEVICE): cv.string, + vol.Required(ATTR_TONE): cv.string, + vol.Required(ATTR_TEXT_MESSAGE): cv.string, + vol.Required(ATTR_VOLUME): vol.All( + vol.Coerce(int), vol.Range(min=0, max=15) + ), + vol.Optional(ATTR_REPEAT, default=0): vol.All( + vol.Coerce(int), vol.Range(min=0, max=10) + ), + }, + ), + service_func=handle_speaker_hub_play_call, + ) diff --git a/homeassistant/components/yolink/services.yaml b/homeassistant/components/yolink/services.yaml new file mode 100644 index 00000000000..939eba3e7f5 --- /dev/null +++ b/homeassistant/components/yolink/services.yaml @@ -0,0 +1,44 @@ +# SpeakerHub service +play_on_speaker_hub: + fields: + target_device: + required: true + selector: + device: + filter: + - integration: yolink + manufacturer: YoLink + model: SpeakerHub + + message: + required: true + example: hello, yolink + selector: + text: + tone: + required: true + default: "tip" + selector: + select: + options: + - "emergency" + - "alert" + - "warn" + - "tip" + translation_key: speaker_tone + volume: + required: true + default: 8 + selector: + number: + min: 0 + max: 15 + step: 1 + repeat: + required: true + default: 0 + selector: + number: + min: 0 + max: 10 + step: 1 diff --git a/homeassistant/components/yolink/strings.json b/homeassistant/components/yolink/strings.json index e1fa09429aa..9661abe096c 100644 --- a/homeassistant/components/yolink/strings.json +++ b/homeassistant/components/yolink/strings.json @@ -75,5 +75,43 @@ "name": "Volume" } } + }, + "services": { + "play_on_speaker_hub": { + "name": "Play on SpeakerHub", + "description": "Convert text to audio play on YoLink SpeakerHub", + "fields": { + "target_device": { + "name": "SpeakerHub Device", + "description": "SpeakerHub Device" + }, + "message": { + "name": "Text message", + "description": "Text message to be played." + }, + "tone": { + "name": "Tone", + "description": "Tone before playing audio." + }, + "volume": { + "name": "Volume", + "description": "Speaker volume during playback." + }, + "repeat": { + "name": "Repeat", + "description": "The amount of times the text will be repeated." + } + } + } + }, + "selector": { + "speaker_tone": { + "options": { + "emergency": "Emergency", + "alert": "Alert", + "warn": "Warn", + "tip": "Tip" + } + } } }