mirror of https://github.com/home-assistant/core
Add chart service to LaMetric (#80554)
This commit is contained in:
parent
ddba653158
commit
e3919babb2
|
@ -19,10 +19,12 @@ LOGGER = logging.getLogger(__package__)
|
|||
SCAN_INTERVAL = timedelta(seconds=30)
|
||||
|
||||
CONF_CYCLES: Final = "cycles"
|
||||
CONF_DATA: Final = "data"
|
||||
CONF_ICON_TYPE: Final = "icon_type"
|
||||
CONF_LIFETIME: Final = "lifetime"
|
||||
CONF_MESSAGE: Final = "message"
|
||||
CONF_PRIORITY: Final = "priority"
|
||||
CONF_SOUND: Final = "sound"
|
||||
CONF_MESSAGE: Final = "message"
|
||||
|
||||
SERVICE_MESSAGE: Final = "message"
|
||||
SERVICE_CHART: Final = "chart"
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
"""Support for LaMetric time services."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
from demetriek import (
|
||||
AlarmSound,
|
||||
Chart,
|
||||
LaMetricError,
|
||||
Model,
|
||||
Notification,
|
||||
|
@ -19,20 +24,21 @@ from homeassistant.helpers import config_validation as cv
|
|||
|
||||
from .const import (
|
||||
CONF_CYCLES,
|
||||
CONF_DATA,
|
||||
CONF_ICON_TYPE,
|
||||
CONF_MESSAGE,
|
||||
CONF_PRIORITY,
|
||||
CONF_SOUND,
|
||||
DOMAIN,
|
||||
SERVICE_CHART,
|
||||
SERVICE_MESSAGE,
|
||||
)
|
||||
from .coordinator import LaMetricDataUpdateCoordinator
|
||||
from .helpers import async_get_coordinator_by_device_id
|
||||
|
||||
SERVICE_MESSAGE_SCHEMA = vol.Schema(
|
||||
SERVICE_BASE_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_DEVICE_ID): cv.string,
|
||||
vol.Required(CONF_MESSAGE): cv.string,
|
||||
vol.Optional(CONF_CYCLES, default=1): cv.positive_int,
|
||||
vol.Optional(CONF_ICON_TYPE, default=NotificationIconType.NONE): vol.Coerce(
|
||||
NotificationIconType
|
||||
|
@ -43,34 +49,73 @@ SERVICE_MESSAGE_SCHEMA = vol.Schema(
|
|||
vol.Optional(CONF_SOUND): vol.Any(
|
||||
vol.Coerce(AlarmSound), vol.Coerce(NotificationSound)
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
SERVICE_MESSAGE_SCHEMA = SERVICE_BASE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_MESSAGE): cv.string,
|
||||
vol.Optional(CONF_ICON): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
SERVICE_CHART_SCHEMA = SERVICE_BASE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_DATA): vol.All(cv.ensure_list, [vol.Coerce(int)]),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def async_setup_services(hass: HomeAssistant) -> None:
|
||||
"""Set up services for the LaMetric integration."""
|
||||
|
||||
async def _async_service_text(call: ServiceCall) -> None:
|
||||
async def _async_service_chart(call: ServiceCall) -> None:
|
||||
"""Send a chart to a LaMetric device."""
|
||||
coordinator = async_get_coordinator_by_device_id(
|
||||
hass, call.data[CONF_DEVICE_ID]
|
||||
)
|
||||
await async_send_notification(
|
||||
coordinator, call, [Chart(data=call.data[CONF_DATA])]
|
||||
)
|
||||
|
||||
async def _async_service_message(call: ServiceCall) -> None:
|
||||
"""Send a message to a LaMetric device."""
|
||||
coordinator = async_get_coordinator_by_device_id(
|
||||
hass, call.data[CONF_DEVICE_ID]
|
||||
)
|
||||
await async_service_text(coordinator, call)
|
||||
await async_send_notification(
|
||||
coordinator,
|
||||
call,
|
||||
[
|
||||
Simple(
|
||||
icon=call.data.get(CONF_ICON),
|
||||
text=call.data[CONF_MESSAGE],
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_CHART,
|
||||
_async_service_chart,
|
||||
schema=SERVICE_CHART_SCHEMA,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_MESSAGE,
|
||||
_async_service_text,
|
||||
_async_service_message,
|
||||
schema=SERVICE_MESSAGE_SCHEMA,
|
||||
)
|
||||
|
||||
|
||||
async def async_service_text(
|
||||
coordinator: LaMetricDataUpdateCoordinator, call: ServiceCall
|
||||
async def async_send_notification(
|
||||
coordinator: LaMetricDataUpdateCoordinator,
|
||||
call: ServiceCall,
|
||||
frames: Sequence[Chart | Simple],
|
||||
) -> None:
|
||||
"""Send a message to an LaMetric device."""
|
||||
"""Send a notification to an LaMetric device."""
|
||||
sound = None
|
||||
if CONF_SOUND in call.data:
|
||||
sound = Sound(id=call.data[CONF_SOUND], category=None)
|
||||
|
@ -79,12 +124,7 @@ async def async_service_text(
|
|||
icon_type=NotificationIconType(call.data[CONF_ICON_TYPE]),
|
||||
priority=NotificationPriority(call.data.get(CONF_PRIORITY)),
|
||||
model=Model(
|
||||
frames=[
|
||||
Simple(
|
||||
icon=call.data.get(CONF_ICON),
|
||||
text=call.data[CONF_MESSAGE],
|
||||
)
|
||||
],
|
||||
frames=frames,
|
||||
cycles=call.data[CONF_CYCLES],
|
||||
sound=sound,
|
||||
),
|
||||
|
|
|
@ -1,29 +1,22 @@
|
|||
message:
|
||||
name: Display a message
|
||||
description: Display a message with an optional icon on a LaMetric device.
|
||||
chart:
|
||||
name: Display a chart
|
||||
description: Display a chart on a LaMetric device.
|
||||
fields:
|
||||
device_id:
|
||||
device_id: &device_id
|
||||
name: Device
|
||||
description: The LaMetric device to display the message on.
|
||||
description: The LaMetric device to display the chart on.
|
||||
required: true
|
||||
selector:
|
||||
device:
|
||||
integration: lametric
|
||||
message:
|
||||
name: Message
|
||||
description: The message to display.
|
||||
data:
|
||||
name: Data
|
||||
description: The list of data points in the chart
|
||||
required: true
|
||||
example: "[1,2,3,4,5,4,3,2,1]"
|
||||
selector:
|
||||
text:
|
||||
icon:
|
||||
name: Icon
|
||||
description: >-
|
||||
The ID number of the icon or animation to display. List of all icons
|
||||
and their IDs can be found at: https://developer.lametric.com/icons
|
||||
required: false
|
||||
selector:
|
||||
text:
|
||||
sound:
|
||||
object:
|
||||
sound: &sound
|
||||
name: Sound
|
||||
description: The notification sound to play.
|
||||
required: false
|
||||
|
@ -126,7 +119,7 @@ message:
|
|||
value: "wind"
|
||||
- label: "Wind short"
|
||||
value: "wind_short"
|
||||
cycles:
|
||||
cycles: &cycles
|
||||
name: Cycles
|
||||
description: >-
|
||||
The number of times to display the message. When set to 0, the message
|
||||
|
@ -138,7 +131,7 @@ message:
|
|||
min: 0
|
||||
max: 10
|
||||
mode: slider
|
||||
icon_type:
|
||||
icon_type: &icon_type
|
||||
name: Icon type
|
||||
description: >-
|
||||
The type of icon to display, indicating the nature of the notification.
|
||||
|
@ -154,7 +147,7 @@ message:
|
|||
value: "info"
|
||||
- label: "Alert"
|
||||
value: "alert"
|
||||
priority:
|
||||
priority: &priority
|
||||
name: Priority
|
||||
description: >-
|
||||
The priority of the notification. When the device is running in
|
||||
|
@ -172,3 +165,27 @@ message:
|
|||
value: "warning"
|
||||
- label: "Critical"
|
||||
value: "critical"
|
||||
|
||||
message:
|
||||
name: Display a message
|
||||
description: Display a message with an optional icon on a LaMetric device.
|
||||
fields:
|
||||
device_id: *device_id
|
||||
message:
|
||||
name: Message
|
||||
description: The message to display.
|
||||
required: true
|
||||
selector:
|
||||
text:
|
||||
icon:
|
||||
name: Icon
|
||||
description: >-
|
||||
The ID number of the icon or animation to display. List of all icons
|
||||
and their IDs can be found at: https://developer.lametric.com/icons
|
||||
required: false
|
||||
selector:
|
||||
text:
|
||||
sound: *sound
|
||||
cycles: *cycles
|
||||
icon_type: *icon_type
|
||||
priority: *priority
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from unittest.mock import MagicMock
|
||||
|
||||
from demetriek import (
|
||||
Chart,
|
||||
LaMetricError,
|
||||
Notification,
|
||||
NotificationIconType,
|
||||
|
@ -14,11 +15,13 @@ import pytest
|
|||
|
||||
from homeassistant.components.lametric.const import (
|
||||
CONF_CYCLES,
|
||||
CONF_DATA,
|
||||
CONF_ICON_TYPE,
|
||||
CONF_MESSAGE,
|
||||
CONF_PRIORITY,
|
||||
CONF_SOUND,
|
||||
DOMAIN,
|
||||
SERVICE_CHART,
|
||||
SERVICE_MESSAGE,
|
||||
)
|
||||
from homeassistant.const import CONF_DEVICE_ID, CONF_ICON
|
||||
|
@ -29,12 +32,100 @@ from homeassistant.helpers import entity_registry as er
|
|||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_service_chart(
|
||||
hass: HomeAssistant,
|
||||
init_integration: MockConfigEntry,
|
||||
mock_lametric: MagicMock,
|
||||
) -> None:
|
||||
"""Test the LaMetric chart service."""
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
entry = entity_registry.async_get("button.frenck_s_lametric_next_app")
|
||||
assert entry
|
||||
assert entry.device_id
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_CHART,
|
||||
{
|
||||
CONF_DEVICE_ID: entry.device_id,
|
||||
CONF_DATA: [1, 2, 3, 4, 5, 4, 3, 2, 1],
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(mock_lametric.notify.mock_calls) == 1
|
||||
|
||||
notification: Notification = mock_lametric.notify.mock_calls[0][2]["notification"]
|
||||
assert notification.icon_type is NotificationIconType.NONE
|
||||
assert notification.life_time is None
|
||||
assert notification.model.cycles == 1
|
||||
assert notification.model.sound is None
|
||||
assert notification.notification_id is None
|
||||
assert notification.notification_type is None
|
||||
assert notification.priority is NotificationPriority.INFO
|
||||
|
||||
assert len(notification.model.frames) == 1
|
||||
frame = notification.model.frames[0]
|
||||
assert type(frame) is Chart
|
||||
assert frame.data == [1, 2, 3, 4, 5, 4, 3, 2, 1]
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_CHART,
|
||||
{
|
||||
CONF_DATA: [1, 2, 3, 4, 5, 4, 3, 2, 1],
|
||||
CONF_DEVICE_ID: entry.device_id,
|
||||
CONF_CYCLES: 3,
|
||||
CONF_ICON_TYPE: "info",
|
||||
CONF_PRIORITY: "critical",
|
||||
CONF_SOUND: "cat",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(mock_lametric.notify.mock_calls) == 2
|
||||
|
||||
notification: Notification = mock_lametric.notify.mock_calls[1][2]["notification"]
|
||||
assert notification.icon_type is NotificationIconType.INFO
|
||||
assert notification.life_time is None
|
||||
assert notification.model.cycles == 3
|
||||
assert notification.model.sound is not None
|
||||
assert notification.model.sound.category is NotificationSoundCategory.NOTIFICATIONS
|
||||
assert notification.model.sound.sound is NotificationSound.CAT
|
||||
assert notification.model.sound.repeat == 1
|
||||
assert notification.notification_id is None
|
||||
assert notification.notification_type is None
|
||||
assert notification.priority is NotificationPriority.CRITICAL
|
||||
|
||||
assert len(notification.model.frames) == 1
|
||||
frame = notification.model.frames[0]
|
||||
assert type(frame) is Chart
|
||||
assert frame.data == [1, 2, 3, 4, 5, 4, 3, 2, 1]
|
||||
|
||||
mock_lametric.notify.side_effect = LaMetricError
|
||||
with pytest.raises(
|
||||
HomeAssistantError, match="Could not send LaMetric notification"
|
||||
):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_CHART,
|
||||
{
|
||||
CONF_DEVICE_ID: entry.device_id,
|
||||
CONF_DATA: [1, 2, 3, 4, 5],
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(mock_lametric.notify.mock_calls) == 3
|
||||
|
||||
|
||||
async def test_service_message(
|
||||
hass: HomeAssistant,
|
||||
init_integration: MockConfigEntry,
|
||||
mock_lametric: MagicMock,
|
||||
) -> None:
|
||||
"""Test the LaMetric text service."""
|
||||
"""Test the LaMetric message service."""
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
entry = entity_registry.async_get("button.frenck_s_lametric_next_app")
|
||||
|
|
Loading…
Reference in New Issue