mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 02:37:08 +00:00
Alexa to handle brightness and catch exceptions (#65322)
This commit is contained in:
parent
0a000babc9
commit
1fbd624a24
@ -1,6 +1,8 @@
|
|||||||
"""Alexa related errors."""
|
"""Alexa related errors."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
|
||||||
from .const import API_TEMP_UNITS
|
from .const import API_TEMP_UNITS
|
||||||
@ -58,6 +60,30 @@ class AlexaInvalidValueError(AlexaError):
|
|||||||
error_type = "INVALID_VALUE"
|
error_type = "INVALID_VALUE"
|
||||||
|
|
||||||
|
|
||||||
|
class AlexaInteralError(AlexaError):
|
||||||
|
"""Class to represent internal errors."""
|
||||||
|
|
||||||
|
namespace = "Alexa"
|
||||||
|
error_type = "INTERNAL_ERROR"
|
||||||
|
|
||||||
|
|
||||||
|
class AlexaNotSupportedInCurrentMode(AlexaError):
|
||||||
|
"""The device is not in the correct mode to support this command."""
|
||||||
|
|
||||||
|
namespace = "Alexa"
|
||||||
|
error_type = "NOT_SUPPORTED_IN_CURRENT_MODE"
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
endpoint_id: str,
|
||||||
|
current_mode: Literal["COLOR", "ASLEEP", "NOT_PROVISIONED", "OTHER"],
|
||||||
|
) -> None:
|
||||||
|
"""Initialize invalid endpoint error."""
|
||||||
|
msg = f"Not supported while in {current_mode} mode"
|
||||||
|
AlexaError.__init__(self, msg, {"currentDeviceMode": current_mode})
|
||||||
|
self.endpoint_id = endpoint_id
|
||||||
|
|
||||||
|
|
||||||
class AlexaUnsupportedThermostatModeError(AlexaError):
|
class AlexaUnsupportedThermostatModeError(AlexaError):
|
||||||
"""Class to represent UnsupportedThermostatMode errors."""
|
"""Class to represent UnsupportedThermostatMode errors."""
|
||||||
|
|
||||||
|
@ -212,20 +212,14 @@ async def async_api_adjust_brightness(hass, config, directive, context):
|
|||||||
entity = directive.entity
|
entity = directive.entity
|
||||||
brightness_delta = int(directive.payload["brightnessDelta"])
|
brightness_delta = int(directive.payload["brightnessDelta"])
|
||||||
|
|
||||||
# read current state
|
|
||||||
try:
|
|
||||||
current = math.floor(
|
|
||||||
int(entity.attributes.get(light.ATTR_BRIGHTNESS)) / 255 * 100
|
|
||||||
)
|
|
||||||
except ZeroDivisionError:
|
|
||||||
current = 0
|
|
||||||
|
|
||||||
# set brightness
|
# set brightness
|
||||||
brightness = max(0, brightness_delta + current)
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
entity.domain,
|
entity.domain,
|
||||||
SERVICE_TURN_ON,
|
SERVICE_TURN_ON,
|
||||||
{ATTR_ENTITY_ID: entity.entity_id, light.ATTR_BRIGHTNESS_PCT: brightness},
|
{
|
||||||
|
ATTR_ENTITY_ID: entity.entity_id,
|
||||||
|
light.ATTR_BRIGHTNESS_STEP_PCT: brightness_delta,
|
||||||
|
},
|
||||||
blocking=False,
|
blocking=False,
|
||||||
context=context,
|
context=context,
|
||||||
)
|
)
|
||||||
|
@ -48,8 +48,18 @@ async def async_handle_message(hass, config, request, context=None, enabled=True
|
|||||||
response = directive.error()
|
response = directive.error()
|
||||||
except AlexaError as err:
|
except AlexaError as err:
|
||||||
response = directive.error(
|
response = directive.error(
|
||||||
error_type=err.error_type, error_message=err.error_message
|
error_type=err.error_type,
|
||||||
|
error_message=err.error_message,
|
||||||
|
payload=err.payload,
|
||||||
)
|
)
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
_LOGGER.exception(
|
||||||
|
"Uncaught exception processing Alexa %s/%s request (%s)",
|
||||||
|
directive.namespace,
|
||||||
|
directive.name,
|
||||||
|
directive.entity_id or "-",
|
||||||
|
)
|
||||||
|
response = directive.error(error_message="Unknown error")
|
||||||
|
|
||||||
request_info = {"namespace": directive.namespace, "name": directive.name}
|
request_info = {"namespace": directive.namespace, "name": directive.name}
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ async def assert_scene_controller_works(
|
|||||||
assert re.search(pattern, response["event"]["payload"]["timestamp"])
|
assert re.search(pattern, response["event"]["payload"]["timestamp"])
|
||||||
|
|
||||||
|
|
||||||
async def reported_properties(hass, endpoint):
|
async def reported_properties(hass, endpoint, return_full_response=False):
|
||||||
"""Use ReportState to get properties and return them.
|
"""Use ReportState to get properties and return them.
|
||||||
|
|
||||||
The result is a ReportedProperties instance, which has methods to make
|
The result is a ReportedProperties instance, which has methods to make
|
||||||
@ -203,6 +203,8 @@ async def reported_properties(hass, endpoint):
|
|||||||
request = get_new_request("Alexa", "ReportState", endpoint)
|
request = get_new_request("Alexa", "ReportState", endpoint)
|
||||||
msg = await smart_home.async_handle_message(hass, get_default_config(), request)
|
msg = await smart_home.async_handle_message(hass, get_default_config(), request)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if return_full_response:
|
||||||
|
return msg
|
||||||
return ReportedProperties(msg["context"]["properties"])
|
return ReportedProperties(msg["context"]["properties"])
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ from unittest.mock import patch
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.alexa import smart_home
|
from homeassistant.components.alexa import smart_home
|
||||||
from homeassistant.components.alexa.errors import UnsupportedProperty
|
|
||||||
from homeassistant.components.climate import const as climate
|
from homeassistant.components.climate import const as climate
|
||||||
from homeassistant.components.lock import STATE_JAMMED, STATE_LOCKING, STATE_UNLOCKING
|
from homeassistant.components.lock import STATE_JAMMED, STATE_LOCKING, STATE_UNLOCKING
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
@ -39,8 +38,8 @@ from . import (
|
|||||||
from tests.common import async_mock_service
|
from tests.common import async_mock_service
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("result,adjust", [(25, "-5"), (35, "5"), (0, "-80")])
|
@pytest.mark.parametrize("adjust", ["-5", "5", "-80"])
|
||||||
async def test_api_adjust_brightness(hass, result, adjust):
|
async def test_api_adjust_brightness(hass, adjust):
|
||||||
"""Test api adjust brightness process."""
|
"""Test api adjust brightness process."""
|
||||||
request = get_new_request(
|
request = get_new_request(
|
||||||
"Alexa.BrightnessController", "AdjustBrightness", "light#test"
|
"Alexa.BrightnessController", "AdjustBrightness", "light#test"
|
||||||
@ -64,7 +63,7 @@ async def test_api_adjust_brightness(hass, result, adjust):
|
|||||||
|
|
||||||
assert len(call_light) == 1
|
assert len(call_light) == 1
|
||||||
assert call_light[0].data["entity_id"] == "light.test"
|
assert call_light[0].data["entity_id"] == "light.test"
|
||||||
assert call_light[0].data["brightness_pct"] == result
|
assert call_light[0].data["brightness_step_pct"] == int(adjust)
|
||||||
assert msg["header"]["name"] == "Response"
|
assert msg["header"]["name"] == "Response"
|
||||||
|
|
||||||
|
|
||||||
@ -677,16 +676,9 @@ async def test_report_climate_state(hass):
|
|||||||
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
|
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
with pytest.raises(UnsupportedProperty):
|
msg = await reported_properties(hass, "climate.unsupported", True)
|
||||||
properties = await reported_properties(hass, "climate.unsupported")
|
assert msg["event"]["header"]["name"] == "ErrorResponse"
|
||||||
properties.assert_not_has_property(
|
assert msg["event"]["payload"]["type"] == "INTERNAL_ERROR"
|
||||||
"Alexa.ThermostatController", "thermostatMode"
|
|
||||||
)
|
|
||||||
properties.assert_equal(
|
|
||||||
"Alexa.TemperatureSensor",
|
|
||||||
"temperature",
|
|
||||||
{"value": 34.0, "scale": "CELSIUS"},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_temperature_sensor_sensor(hass):
|
async def test_temperature_sensor_sensor(hass):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user