Skip to content

Commit

Permalink
feat: Add restore volume service (#2773)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielbrunt57 authored Dec 28, 2024
1 parent c107046 commit eca4ef6
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 29 deletions.
1 change: 1 addition & 0 deletions custom_components/alexa_media/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
DEFAULT_SCAN_INTERVAL = 60

SERVICE_UPDATE_LAST_CALLED = "update_last_called"
SERVICE_RESTORE_VOLUME = "restore_volume"
SERVICE_FORCE_LOGOUT = "force_logout"

RECURRING_PATTERN = {
Expand Down
73 changes: 64 additions & 9 deletions custom_components/alexa_media/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@

from alexapy import AlexaAPI, AlexapyLoginError, hide_email
from alexapy.errors import AlexapyConnectionError
from homeassistant.helpers import config_validation as cv
from homeassistant.const import ATTR_DEVICE_ID, ATTR_ENTITY_ID
from homeassistant.helpers import config_validation as cv, entity_registry as er
import voluptuous as vol

from .const import (
Expand All @@ -21,6 +22,7 @@
DATA_ALEXAMEDIA,
DOMAIN,
SERVICE_FORCE_LOGOUT,
SERVICE_RESTORE_VOLUME,
SERVICE_UPDATE_LAST_CALLED,
)
from .helpers import _catch_login_errors, report_relogin_required
Expand All @@ -34,6 +36,7 @@
LAST_CALL_UPDATE_SCHEMA = vol.Schema(
{vol.Optional(ATTR_EMAIL, default=[]): vol.All(cv.ensure_list, [cv.string])}
)
RESTORE_VOLUME_SCHEMA = vol.Schema({vol.Required(ATTR_ENTITY_ID): cv.entity_id})


class AlexaMediaServices:
Expand All @@ -46,31 +49,41 @@ def __init__(self, hass, functions: dict[str, Callable]):

async def register(self):
"""Register services to hass."""
self.hass.services.async_register(
DOMAIN, SERVICE_FORCE_LOGOUT, self.force_logout, schema=FORCE_LOGOUT_SCHEMA
)
self.hass.services.async_register(
DOMAIN,
SERVICE_UPDATE_LAST_CALLED,
self.last_call_handler,
schema=LAST_CALL_UPDATE_SCHEMA,
)
self.hass.services.async_register(
DOMAIN, SERVICE_FORCE_LOGOUT, self.force_logout, schema=FORCE_LOGOUT_SCHEMA
DOMAIN,
SERVICE_RESTORE_VOLUME,
self.restore_volume,
schema=RESTORE_VOLUME_SCHEMA,
)

async def unregister(self):
"""Register services to hass."""
"""Deregister services from hass."""
self.hass.services.async_remove(DOMAIN, SERVICE_FORCE_LOGOUT)
self.hass.services.async_remove(
DOMAIN,
SERVICE_UPDATE_LAST_CALLED,
)
self.hass.services.async_remove(DOMAIN, SERVICE_FORCE_LOGOUT)
self.hass.services.async_remove(
DOMAIN,
SERVICE_RESTORE_VOLUME,
)

@_catch_login_errors
async def force_logout(self, call) -> bool:
"""Handle force logout service request.
Arguments
call.ATTR_EMAIL {List[str: None]} -- Case-sensitive Alexa emails.
Default is all known emails.
call.ATTR_EMAIL {List[str: None]}: List of case-sensitive Alexa emails.
If None, all accounts are logged out.
Returns
bool -- True if force logout successful
Expand All @@ -97,12 +110,13 @@ async def force_logout(self, call) -> bool:
)
return success

@_catch_login_errors
async def last_call_handler(self, call):
"""Handle last call service request.
Args
call: List of case-sensitive Alexa email addresses. If None
all accounts are updated.
Arguments
call.ATTR_EMAIL: {List[str: None]}: List of case-sensitive Alexa emails.
If None, all accounts are updated.
"""
requested_emails = call.data.get(ATTR_EMAIL)
Expand All @@ -121,3 +135,44 @@ async def last_call_handler(self, call):
" check your network connection and try again",
hide_email(email),
)

async def restore_volume(self, call) -> bool:
"""Handle restore volume service request.
Arguments
call.ATTR_ENTITY_ID {str: None} -- Alexa media player entity.
"""
entity_id = call.data.get(ATTR_ENTITY_ID)
_LOGGER.debug("Service restore_volume called for: %s", entity_id)

# Retrieve the entity registry and entity entry
entity_registry = er.async_get(self.hass)
entity_entry = entity_registry.async_get(entity_id)

if not entity_entry:
_LOGGER.error("Entity %s not found in registry", entity_id)
return False

# Retrieve the previous volume from the entity's state attributes
state = self.hass.states.get(entity_id)
if not state or "previous_volume" not in state.attributes:
_LOGGER.error(
"Previous volume attribute not found for entity %s", entity_id
)
return False

previous_volume = state.attributes["previous_volume"]

# Call the volume_set service with the retrieved volume
await self.hass.services.async_call(
domain="media_player",
service="volume_set",
service_data={
"volume_level": previous_volume,
},
target={"entity_id": entity_id},
)

_LOGGER.debug("Volume restored to %s for entity %s", previous_volume, entity_id)
return True
24 changes: 18 additions & 6 deletions custom_components/alexa_media/services.yaml
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
# SPDX-License-Identifier: Apache-2.0
update_last_called:
force_logout:
# Description of the service
description: Forces update of last_called echo device for each Alexa account.
description: Force logout of Alexa Login account and deletion of .pickle. Intended for debugging use.
# Different fields that your service accepts
fields:
# Key of the field
email:
# Description of the field
description: List of Alexa accounts to update. If empty, will update all known accounts.
description: List of Alexa accounts to log out. If empty, will log out from all known accounts.
# Example value that can be passed for this field
example: "my_email@alexa.com"

force_logout:
restore_volume:
description: Restores an Alexa Media Player volume level to the previous volume level.
fields:
entity_id:
name: Entity
description: Alexa Media Player device to restore volume on.
required: true
selector:
entity:
domain: media_player
integration: alexa_media

update_last_called:
# Description of the service
description: Force logout of Alexa Login account and deletion of .pickle. Intended for debugging use.
description: Forces update of last_called echo device for each Alexa account.
# Different fields that your service accepts
fields:
# Key of the field
email:
# Description of the field
description: List of Alexa accounts to log out. If empty, will log out from all known accounts.
description: List of Alexa accounts to update. If empty, will update all known accounts.
# Example value that can be passed for this field
example: "my_email@alexa.com"
10 changes: 10 additions & 0 deletions custom_components/alexa_media/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@
}
}
},
"restore_volume": {
"description": "Restore previous volume level on Alexa media player device",
"fields": {
"entity_id": {
"description": "Entity to restore the previous volume level on",
"name": "Select media player:"
}
},
"name": "Restore Previous Volume"
},
"update_last_called": {
"name": "Update Last Called Sensor",
"description": "Forces update of last_called echo device for each Alexa account.",
Expand Down
24 changes: 10 additions & 14 deletions custom_components/alexa_media/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,6 @@
}
},
"services": {
"clear_history": {
"description": "Clear last entries from Alexa Voice history for each Alexa account.",
"fields": {
"email": {
"description": "Accounts to clear. Empty will clear all.",
"name": "Email address"
},
"entries": {
"description": "Number of entries to clear from 1 to 50. If empty, clear 50.",
"name": "Number of Entries"
}
},
"name": "Clear Amazon Voice History"
},
"force_logout": {
"description": "Force account to logout. Used mainly for debugging.",
"fields": {
Expand All @@ -92,6 +78,16 @@
},
"name": "Force Logout"
},
"restore_volume":{
"description":"Restore previous volume setting on Alexa media player device",
"fields": {
"entity_id": {
"description": "Entity to restore the previous volume level on",
"name": "Select media player:"
}
},
"name":"Restore Previous Volume"
},
"update_last_called": {
"description": "Forces update of last_called echo device for each Alexa account.",
"fields": {
Expand Down

0 comments on commit eca4ef6

Please sign in to comment.