Discover switch entities from Hue behavior_script instances (#101262)

This commit is contained in:
Marcel van der Veldt 2023-10-02 17:15:41 +02:00 committed by GitHub
parent 054407722d
commit 35616e100d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 37 deletions

View File

@ -104,6 +104,14 @@
"unidirectional_incoming": "Unidirectional incoming" "unidirectional_incoming": "Unidirectional incoming"
} }
} }
},
"switch": {
"automation": {
"state": {
"on": "[%key:common::state::enabled%",
"off": "[%key:common::state::disabled%"
}
}
} }
}, },
"options": { "options": {

View File

@ -4,6 +4,7 @@ from __future__ import annotations
from typing import Any, TypeAlias from typing import Any, TypeAlias
from aiohue.v2 import HueBridgeV2 from aiohue.v2 import HueBridgeV2
from aiohue.v2.controllers.config import BehaviorInstance, BehaviorInstanceController
from aiohue.v2.controllers.events import EventType from aiohue.v2.controllers.events import EventType
from aiohue.v2.controllers.sensors import ( from aiohue.v2.controllers.sensors import (
LightLevel, LightLevel,
@ -12,7 +13,11 @@ from aiohue.v2.controllers.sensors import (
MotionController, MotionController,
) )
from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity from homeassistant.components.switch import (
SwitchDeviceClass,
SwitchEntity,
SwitchEntityDescription,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
@ -22,7 +27,9 @@ from .bridge import HueBridge
from .const import DOMAIN from .const import DOMAIN
from .v2.entity import HueBaseEntity from .v2.entity import HueBaseEntity
ControllerType: TypeAlias = LightLevelController | MotionController ControllerType: TypeAlias = (
BehaviorInstanceController | LightLevelController | MotionController
)
SensingService: TypeAlias = LightLevel | Motion SensingService: TypeAlias = LightLevel | Motion
@ -43,11 +50,18 @@ async def async_setup_entry(
@callback @callback
def register_items(controller: ControllerType): def register_items(controller: ControllerType):
@callback @callback
def async_add_entity(event_type: EventType, resource: SensingService) -> None: def async_add_entity(
event_type: EventType, resource: SensingService | BehaviorInstance
) -> None:
"""Add entity from Hue resource.""" """Add entity from Hue resource."""
async_add_entities( if isinstance(resource, BehaviorInstance):
[HueSensingServiceEnabledEntity(bridge, controller, resource)] async_add_entities(
) [HueBehaviorInstanceEnabledEntity(bridge, controller, resource)]
)
else:
async_add_entities(
[HueSensingServiceEnabledEntity(bridge, controller, resource)]
)
# add all current items in controller # add all current items in controller
for item in controller: for item in controller:
@ -63,24 +77,13 @@ async def async_setup_entry(
# setup for each switch-type hue resource # setup for each switch-type hue resource
register_items(api.sensors.motion) register_items(api.sensors.motion)
register_items(api.sensors.light_level) register_items(api.sensors.light_level)
register_items(api.config.behavior_instance)
class HueSensingServiceEnabledEntity(HueBaseEntity, SwitchEntity): class HueResourceEnabledEntity(HueBaseEntity, SwitchEntity):
"""Representation of a Switch entity from Hue SensingService.""" """Representation of a Switch entity from a Hue resource that can be toggled enabled."""
_attr_entity_category = EntityCategory.CONFIG controller: BehaviorInstanceController | LightLevelController | MotionController
_attr_device_class = SwitchDeviceClass.SWITCH
def __init__(
self,
bridge: HueBridge,
controller: LightLevelController | MotionController,
resource: SensingService,
) -> None:
"""Initialize the entity."""
super().__init__(bridge, controller, resource)
self.resource = resource
self.controller = controller
@property @property
def is_on(self) -> bool: def is_on(self) -> bool:
@ -98,3 +101,32 @@ class HueSensingServiceEnabledEntity(HueBaseEntity, SwitchEntity):
await self.bridge.async_request_call( await self.bridge.async_request_call(
self.controller.set_enabled, self.resource.id, enabled=False self.controller.set_enabled, self.resource.id, enabled=False
) )
class HueSensingServiceEnabledEntity(HueResourceEnabledEntity):
"""Representation of a Switch entity from Hue SensingService."""
entity_description = SwitchEntityDescription(
key="behavior_instance",
device_class=SwitchDeviceClass.SWITCH,
entity_category=EntityCategory.CONFIG,
)
class HueBehaviorInstanceEnabledEntity(HueResourceEnabledEntity):
"""Representation of a Switch entity to enable/disable a Hue Behavior Instance."""
resource: BehaviorInstance
entity_description = SwitchEntityDescription(
key="behavior_instance",
device_class=SwitchDeviceClass.SWITCH,
entity_category=EntityCategory.CONFIG,
has_entity_name=False,
translation_key="automation",
)
@property
def name(self) -> str:
"""Return name for this entity."""
return f"Automation: {self.resource.metadata.name}"

View File

@ -2050,37 +2050,53 @@
"type": "temperature" "type": "temperature"
}, },
{ {
"id": "9ad57767-e622-4f91-9086-2e5573bc781b",
"type": "behavior_instance",
"script_id": "e73bc72d-96b1-46f8-aa57-729861f80c78",
"enabled": true,
"state": {
"timer_state": "stopped"
},
"configuration": { "configuration": {
"end_state": "last_state", "duration": {
"seconds": 60
},
"what": [
{
"group": {
"rid": "5e799732-e82e-46ab-b5d9-52b701bd7cbc",
"rtype": "room"
},
"recall": {
"rid": "732ff1d9-76a7-4630-aad0-c8acc499bb0b",
"rtype": "recipe"
}
}
],
"where": [ "where": [
{ {
"group": { "group": {
"rid": "c14cf1cf-6c7a-4984-b8bb-c5b71aeb70fc", "rid": "5e799732-e82e-46ab-b5d9-52b701bd7cbc",
"rtype": "entertainment_configuration" "rtype": "room"
} }
} }
] ]
}, },
"dependees": [ "dependees": [
{ {
"level": "critical",
"target": { "target": {
"rid": "c14cf1cf-6c7a-4984-b8bb-c5b71aeb70fc", "rid": "5e799732-e82e-46ab-b5d9-52b701bd7cbc",
"rtype": "entertainment_configuration" "rtype": "room"
}, },
"level": "critical",
"type": "ResourceDependee" "type": "ResourceDependee"
} }
], ],
"enabled": true, "status": "running",
"id": "0670cfb1-2bd7-4237-a0e3-1827a44d7231",
"last_error": "", "last_error": "",
"metadata": { "metadata": {
"name": "state_after_streaming" "name": "Timer Test"
}, }
"migrated_from": "/resourcelinks/47450",
"script_id": "7719b841-6b3d-448d-a0e7-601ae9edb6a2",
"status": "running",
"type": "behavior_instance"
}, },
{ {
"configuration_schema": { "configuration_schema": {

View File

@ -14,8 +14,8 @@ async def test_switch(
await setup_platform(hass, mock_bridge_v2, "switch") await setup_platform(hass, mock_bridge_v2, "switch")
# there shouldn't have been any requests at this point # there shouldn't have been any requests at this point
assert len(mock_bridge_v2.mock_requests) == 0 assert len(mock_bridge_v2.mock_requests) == 0
# 3 entities should be created from test data # 4 entities should be created from test data
assert len(hass.states.async_all()) == 3 assert len(hass.states.async_all()) == 4
# test config switch to enable/disable motion sensor # test config switch to enable/disable motion sensor
test_entity = hass.states.get("switch.hue_motion_sensor_motion") test_entity = hass.states.get("switch.hue_motion_sensor_motion")
@ -24,6 +24,13 @@ async def test_switch(
assert test_entity.state == "on" assert test_entity.state == "on"
assert test_entity.attributes["device_class"] == "switch" assert test_entity.attributes["device_class"] == "switch"
# test config switch to enable/disable a behavior_instance resource (=builtin automation)
test_entity = hass.states.get("switch.automation_timer_test")
assert test_entity is not None
assert test_entity.name == "Automation: Timer Test"
assert test_entity.state == "on"
assert test_entity.attributes["device_class"] == "switch"
async def test_switch_turn_on_service( async def test_switch_turn_on_service(
hass: HomeAssistant, mock_bridge_v2, v2_resources_test_data hass: HomeAssistant, mock_bridge_v2, v2_resources_test_data