Support setting Aqara Hub Volume via homekit_controller (#62538)
This commit is contained in:
parent
6806b8b116
commit
d3d6965ba0
9 changed files with 101 additions and 51 deletions
|
@ -47,6 +47,7 @@ HOMEKIT_ACCESSORY_DISPATCH = {
|
||||||
}
|
}
|
||||||
|
|
||||||
CHARACTERISTIC_PLATFORMS = {
|
CHARACTERISTIC_PLATFORMS = {
|
||||||
|
CharacteristicsTypes.Vendor.AQARA_GATEWAY_VOLUME: "number",
|
||||||
CharacteristicsTypes.Vendor.EVE_ENERGY_WATT: "sensor",
|
CharacteristicsTypes.Vendor.EVE_ENERGY_WATT: "sensor",
|
||||||
CharacteristicsTypes.Vendor.EVE_DEGREE_AIR_PRESSURE: "sensor",
|
CharacteristicsTypes.Vendor.EVE_DEGREE_AIR_PRESSURE: "sensor",
|
||||||
CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION: "number",
|
CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION: "number",
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "HomeKit Controller",
|
"name": "HomeKit Controller",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
|
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
|
||||||
"requirements": ["aiohomekit==0.6.4"],
|
"requirements": ["aiohomekit==0.6.10"],
|
||||||
"zeroconf": ["_hap._tcp.local."],
|
"zeroconf": ["_hap._tcp.local."],
|
||||||
"after_dependencies": ["zeroconf"],
|
"after_dependencies": ["zeroconf"],
|
||||||
"codeowners": ["@Jc2k", "@bdraco"],
|
"codeowners": ["@Jc2k", "@bdraco"],
|
||||||
|
|
|
@ -10,6 +10,7 @@ from aiohomekit.model.characteristics import Characteristic, CharacteristicsType
|
||||||
|
|
||||||
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
|
|
||||||
from . import KNOWN_DEVICES, CharacteristicEntity
|
from . import KNOWN_DEVICES, CharacteristicEntity
|
||||||
|
|
||||||
|
@ -18,11 +19,25 @@ NUMBER_ENTITIES: dict[str, NumberEntityDescription] = {
|
||||||
key=CharacteristicsTypes.Vendor.VOCOLINC_HUMIDIFIER_SPRAY_LEVEL,
|
key=CharacteristicsTypes.Vendor.VOCOLINC_HUMIDIFIER_SPRAY_LEVEL,
|
||||||
name="Spray Quantity",
|
name="Spray Quantity",
|
||||||
icon="mdi:water",
|
icon="mdi:water",
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
),
|
),
|
||||||
CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION: NumberEntityDescription(
|
CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION: NumberEntityDescription(
|
||||||
key=CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION,
|
key=CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION,
|
||||||
name="Elevation",
|
name="Elevation",
|
||||||
icon="mdi:elevation-rise",
|
icon="mdi:elevation-rise",
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
),
|
||||||
|
CharacteristicsTypes.Vendor.AQARA_GATEWAY_VOLUME: NumberEntityDescription(
|
||||||
|
key=CharacteristicsTypes.Vendor.AQARA_GATEWAY_VOLUME,
|
||||||
|
name="Volume",
|
||||||
|
icon="mdi:volume-high",
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
),
|
||||||
|
CharacteristicsTypes.Vendor.AQARA_E1_GATEWAY_VOLUME: NumberEntityDescription(
|
||||||
|
key=CharacteristicsTypes.Vendor.AQARA_E1_GATEWAY_VOLUME,
|
||||||
|
name="Volume",
|
||||||
|
icon="mdi:volume-high",
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +72,14 @@ class HomeKitNumber(CharacteristicEntity, NumberEntity):
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
super().__init__(conn, info, char)
|
super().__init__(conn, info, char)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
"""Return the name of the device if any."""
|
||||||
|
prefix = ""
|
||||||
|
if name := super().name:
|
||||||
|
prefix = f"{name} -"
|
||||||
|
return f"{prefix} {self.entity_description.name}"
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity is tracking."""
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
return [self._char.type]
|
return [self._char.type]
|
||||||
|
|
|
@ -186,7 +186,7 @@ aioguardian==2021.11.0
|
||||||
aioharmony==0.2.8
|
aioharmony==0.2.8
|
||||||
|
|
||||||
# homeassistant.components.homekit_controller
|
# homeassistant.components.homekit_controller
|
||||||
aiohomekit==0.6.4
|
aiohomekit==0.6.10
|
||||||
|
|
||||||
# homeassistant.components.emulated_hue
|
# homeassistant.components.emulated_hue
|
||||||
# homeassistant.components.http
|
# homeassistant.components.http
|
||||||
|
|
|
@ -130,7 +130,7 @@ aioguardian==2021.11.0
|
||||||
aioharmony==0.2.8
|
aioharmony==0.2.8
|
||||||
|
|
||||||
# homeassistant.components.homekit_controller
|
# homeassistant.components.homekit_controller
|
||||||
aiohomekit==0.6.4
|
aiohomekit==0.6.10
|
||||||
|
|
||||||
# homeassistant.components.emulated_hue
|
# homeassistant.components.emulated_hue
|
||||||
# homeassistant.components.http
|
# homeassistant.components.http
|
||||||
|
|
|
@ -3,9 +3,14 @@ Regression tests for Aqara Gateway V3.
|
||||||
|
|
||||||
https://github.com/home-assistant/core/issues/20957
|
https://github.com/home-assistant/core/issues/20957
|
||||||
"""
|
"""
|
||||||
|
from homeassistant.components.alarm_control_panel import (
|
||||||
|
SUPPORT_ALARM_ARM_AWAY,
|
||||||
|
SUPPORT_ALARM_ARM_HOME,
|
||||||
|
SUPPORT_ALARM_ARM_NIGHT,
|
||||||
|
)
|
||||||
from homeassistant.components.light import SUPPORT_BRIGHTNESS, SUPPORT_COLOR
|
from homeassistant.components.light import SUPPORT_BRIGHTNESS, SUPPORT_COLOR
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
|
|
||||||
from tests.components.homekit_controller.common import (
|
from tests.components.homekit_controller.common import (
|
||||||
Helper,
|
Helper,
|
||||||
|
@ -20,44 +25,58 @@ async def test_aqara_gateway_setup(hass):
|
||||||
config_entry, pairing = await setup_test_accessories(hass, accessories)
|
config_entry, pairing = await setup_test_accessories(hass, accessories)
|
||||||
|
|
||||||
entity_registry = er.async_get(hass)
|
entity_registry = er.async_get(hass)
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
|
||||||
# Check that the light is correctly found and set up
|
sensors = [
|
||||||
alarm_id = "alarm_control_panel.aqara_hub_1563"
|
(
|
||||||
alarm = entity_registry.async_get(alarm_id)
|
|
||||||
assert alarm.unique_id == "homekit-0000000123456789-66304"
|
|
||||||
|
|
||||||
alarm_helper = Helper(
|
|
||||||
hass,
|
|
||||||
"alarm_control_panel.aqara_hub_1563",
|
"alarm_control_panel.aqara_hub_1563",
|
||||||
|
"homekit-0000000123456789-66304",
|
||||||
|
"Aqara Hub-1563",
|
||||||
|
SUPPORT_ALARM_ARM_NIGHT | SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"light.aqara_hub_1563",
|
||||||
|
"homekit-0000000123456789-65792",
|
||||||
|
"Aqara Hub-1563",
|
||||||
|
SUPPORT_BRIGHTNESS | SUPPORT_COLOR,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"number.aqara_hub_1563_volume",
|
||||||
|
"homekit-0000000123456789-aid:1-sid:65536-cid:65541",
|
||||||
|
"Aqara Hub-1563 - Volume",
|
||||||
|
None,
|
||||||
|
EntityCategory.CONFIG,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
device_ids = set()
|
||||||
|
|
||||||
|
for (entity_id, unique_id, friendly_name, supported_features, category) in sensors:
|
||||||
|
entry = entity_registry.async_get(entity_id)
|
||||||
|
assert entry.unique_id == unique_id
|
||||||
|
assert entry.entity_category == category
|
||||||
|
|
||||||
|
helper = Helper(
|
||||||
|
hass,
|
||||||
|
entity_id,
|
||||||
pairing,
|
pairing,
|
||||||
accessories[0],
|
accessories[0],
|
||||||
config_entry,
|
config_entry,
|
||||||
)
|
)
|
||||||
alarm_state = await alarm_helper.poll_and_get_state()
|
state = await helper.poll_and_get_state()
|
||||||
assert alarm_state.attributes["friendly_name"] == "Aqara Hub-1563"
|
assert state.attributes["friendly_name"] == friendly_name
|
||||||
|
assert state.attributes.get("supported_features") == supported_features
|
||||||
|
|
||||||
# Check that the light is correctly found and set up
|
device = device_registry.async_get(entry.device_id)
|
||||||
light = entity_registry.async_get("light.aqara_hub_1563")
|
|
||||||
assert light.unique_id == "homekit-0000000123456789-65792"
|
|
||||||
|
|
||||||
light_helper = Helper(
|
|
||||||
hass, "light.aqara_hub_1563", pairing, accessories[0], config_entry
|
|
||||||
)
|
|
||||||
light_state = await light_helper.poll_and_get_state()
|
|
||||||
assert light_state.attributes["friendly_name"] == "Aqara Hub-1563"
|
|
||||||
assert light_state.attributes["supported_features"] == (
|
|
||||||
SUPPORT_BRIGHTNESS | SUPPORT_COLOR
|
|
||||||
)
|
|
||||||
|
|
||||||
device_registry = dr.async_get(hass)
|
|
||||||
|
|
||||||
# All the entities are services of the same accessory
|
|
||||||
# So it looks at the protocol like a single physical device
|
|
||||||
assert alarm.device_id == light.device_id
|
|
||||||
|
|
||||||
device = device_registry.async_get(light.device_id)
|
|
||||||
assert device.manufacturer == "Aqara"
|
assert device.manufacturer == "Aqara"
|
||||||
assert device.name == "Aqara Hub-1563"
|
assert device.name == "Aqara Hub-1563"
|
||||||
assert device.model == "ZHWA11LM"
|
assert device.model == "ZHWA11LM"
|
||||||
assert device.sw_version == "1.4.7"
|
assert device.sw_version == "1.4.7"
|
||||||
assert device.via_device_id is None
|
assert device.via_device_id is None
|
||||||
|
|
||||||
|
device_ids.add(entry.device_id)
|
||||||
|
|
||||||
|
# All entities should be part of same device
|
||||||
|
assert len(device_ids) == 1
|
||||||
|
|
|
@ -39,9 +39,9 @@ async def test_eve_degree_setup(hass):
|
||||||
"Eve Degree AA11 Battery",
|
"Eve Degree AA11 Battery",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"number.eve_degree_aa11",
|
"number.eve_degree_aa11_elevation",
|
||||||
"homekit-AA00A0A00000-aid:1-sid:30-cid:33",
|
"homekit-AA00A0A00000-aid:1-sid:30-cid:33",
|
||||||
"Eve Degree AA11",
|
"Eve Degree AA11 - Elevation",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,21 @@ async def test_vocolinc_flowerbud_setup(hass):
|
||||||
|
|
||||||
# Check that the switch entity is handled correctly
|
# Check that the switch entity is handled correctly
|
||||||
|
|
||||||
entry = entity_registry.async_get("number.vocolinc_flowerbud_0d324b")
|
entry = entity_registry.async_get("number.vocolinc_flowerbud_0d324b_spray_quantity")
|
||||||
assert entry.unique_id == "homekit-AM01121849000327-aid:1-sid:30-cid:38"
|
assert entry.unique_id == "homekit-AM01121849000327-aid:1-sid:30-cid:38"
|
||||||
|
|
||||||
helper = Helper(
|
helper = Helper(
|
||||||
hass, "number.vocolinc_flowerbud_0d324b", pairing, accessories[0], config_entry
|
hass,
|
||||||
|
"number.vocolinc_flowerbud_0d324b_spray_quantity",
|
||||||
|
pairing,
|
||||||
|
accessories[0],
|
||||||
|
config_entry,
|
||||||
)
|
)
|
||||||
state = await helper.poll_and_get_state()
|
state = await helper.poll_and_get_state()
|
||||||
assert state.attributes["friendly_name"] == "VOCOlinc-Flowerbud-0d324b"
|
assert (
|
||||||
|
state.attributes["friendly_name"]
|
||||||
|
== "VOCOlinc-Flowerbud-0d324b - Spray Quantity"
|
||||||
|
)
|
||||||
|
|
||||||
device = device_registry.async_get(entry.device_id)
|
device = device_registry.async_get(entry.device_id)
|
||||||
assert device.manufacturer == "VOCOlinc"
|
assert device.manufacturer == "VOCOlinc"
|
||||||
|
|
|
@ -33,7 +33,7 @@ async def test_read_number(hass, utcnow):
|
||||||
# Helper will be for the primary entity, which is the outlet. Make a helper for the sensor.
|
# Helper will be for the primary entity, which is the outlet. Make a helper for the sensor.
|
||||||
energy_helper = Helper(
|
energy_helper = Helper(
|
||||||
hass,
|
hass,
|
||||||
"number.testdevice",
|
"number.testdevice_spray_quantity",
|
||||||
helper.pairing,
|
helper.pairing,
|
||||||
helper.accessory,
|
helper.accessory,
|
||||||
helper.config_entry,
|
helper.config_entry,
|
||||||
|
@ -61,7 +61,7 @@ async def test_write_number(hass, utcnow):
|
||||||
# Helper will be for the primary entity, which is the outlet. Make a helper for the sensor.
|
# Helper will be for the primary entity, which is the outlet. Make a helper for the sensor.
|
||||||
energy_helper = Helper(
|
energy_helper = Helper(
|
||||||
hass,
|
hass,
|
||||||
"number.testdevice",
|
"number.testdevice_spray_quantity",
|
||||||
helper.pairing,
|
helper.pairing,
|
||||||
helper.accessory,
|
helper.accessory,
|
||||||
helper.config_entry,
|
helper.config_entry,
|
||||||
|
@ -73,7 +73,7 @@ async def test_write_number(hass, utcnow):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"number",
|
"number",
|
||||||
"set_value",
|
"set_value",
|
||||||
{"entity_id": "number.testdevice", "value": 5},
|
{"entity_id": "number.testdevice_spray_quantity", "value": 5},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
assert spray_level.value == 5
|
assert spray_level.value == 5
|
||||||
|
@ -81,7 +81,7 @@ async def test_write_number(hass, utcnow):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"number",
|
"number",
|
||||||
"set_value",
|
"set_value",
|
||||||
{"entity_id": "number.testdevice", "value": 3},
|
{"entity_id": "number.testdevice_spray_quantity", "value": 3},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
assert spray_level.value == 3
|
assert spray_level.value == 3
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue