mirror of
https://github.com/home-assistant/core.git
synced 2025-11-12 04:20:17 +00:00
Add support for air purifiers in HomeKit (#142467)
* Add support for air purifier type in HomeKit. Any fan and PM2.5 in the same device will be treated as an air purifier. type_air_purifiers.py heavily based on type_fans.py - I tried extending type_fans.py but this looked better to me. * Refactor to make AirPurifier class extend Fan. * Ensure all chars are added before creating service * Add support for switching automatic mode. * Add test for auto/manual switch * Add support for air purifier type in HomeKit. Any fan and PM2.5 in the same device will be treated as an air purifier. type_air_purifiers.py heavily based on type_fans.py - I tried extending type_fans.py but this looked better to me. * Add support for air purifier type in HomeKit. Any fan and PM2.5 in the same device will be treated as an air purifier. type_air_purifiers.py heavily based on type_fans.py - I tried extending type_fans.py but this looked better to me. * Refactor to make AirPurifier class extend Fan. * Ensure all chars are added before creating service * Add support for switching automatic mode. * Add test for auto/manual switch * Add support for air purifier type in HomeKit. Any fan and PM2.5 in the same device will be treated as an air purifier. type_air_purifiers.py heavily based on type_fans.py - I tried extending type_fans.py but this looked better to me. * Improve fan config: allow setting fan type (fan or air purifier) Be more explicit than assuming a fan is an air purifier if it has a PM2.5 sensor. Set defaults based on the presence of sensors. * Fix return type annotation for fan/air purifier create_services * Allow linking air purifier filter level/change indicator * Remove no longer needed if statement in fan init * Fix up types and clean up code * Update homekit tests to account for air purifiers * Fix pylint errors * Fix mypy errors * Improve type annotations * Improve readability of auto preset mode discovery * Test air purifier with 'Auto' preset mode * Handle case with a single preset mode * Test air purifier edge cases: state updates to same value, and removed linked entities * Don't create 'auto mode' switch for air purifiers This is already exposed as a target mode on the air purifier service itself * Handle unavailable states in air purifier Also don't remove device class when updating state in test * Reduce branching in air purifier test * Split up air purifier tests for with and without auto presets, to reduce branching * Handle unavailable states in air purifier more explicitly * Use constant for ignored state values * Use a set for ignored_states * Update tests/components/homekit/test_type_air_purifiers.py --------- Co-authored-by: Andrew Kurowski <62596884+ak6i@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick+github@koston.org> Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
@@ -21,6 +21,7 @@ from homeassistant.components.homekit import (
|
||||
STATUS_RUNNING,
|
||||
STATUS_STOPPED,
|
||||
STATUS_WAIT,
|
||||
TYPE_AIR_PURIFIER,
|
||||
HomeKit,
|
||||
)
|
||||
from homeassistant.components.homekit.accessories import HomeBridge
|
||||
@@ -51,6 +52,7 @@ from homeassistant.const import (
|
||||
ATTR_DEVICE_ID,
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONF_NAME,
|
||||
CONF_PORT,
|
||||
EVENT_HOMEASSISTANT_STARTED,
|
||||
@@ -58,6 +60,7 @@ from homeassistant.const import (
|
||||
SERVICE_RELOAD,
|
||||
STATE_ON,
|
||||
EntityCategory,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, State
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
@@ -2162,6 +2165,109 @@ async def test_homekit_finds_linked_humidity_sensors(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_async_zeroconf")
|
||||
async def test_homekit_finds_linked_air_purifier_sensors(
|
||||
hass: HomeAssistant,
|
||||
hk_driver,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test HomeKit start method."""
|
||||
entry = await async_init_integration(hass)
|
||||
|
||||
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
||||
|
||||
homekit.driver = hk_driver
|
||||
homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge")
|
||||
|
||||
config_entry = MockConfigEntry(domain="air_purifier", data={})
|
||||
config_entry.add_to_hass(hass)
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
sw_version="0.16.1",
|
||||
model="Smart Air Purifier",
|
||||
manufacturer="Home Assistant",
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||
)
|
||||
|
||||
humidity_sensor = entity_registry.async_get_or_create(
|
||||
"sensor",
|
||||
"air_purifier",
|
||||
"humidity_sensor",
|
||||
device_id=device_entry.id,
|
||||
original_device_class=SensorDeviceClass.HUMIDITY,
|
||||
)
|
||||
pm25_sensor = entity_registry.async_get_or_create(
|
||||
"sensor",
|
||||
"air_purifier",
|
||||
"pm25_sensor",
|
||||
device_id=device_entry.id,
|
||||
original_device_class=SensorDeviceClass.PM25,
|
||||
)
|
||||
temperature_sensor = entity_registry.async_get_or_create(
|
||||
"sensor",
|
||||
"air_purifier",
|
||||
"temperature_sensor",
|
||||
device_id=device_entry.id,
|
||||
original_device_class=SensorDeviceClass.TEMPERATURE,
|
||||
)
|
||||
air_purifier = entity_registry.async_get_or_create(
|
||||
"fan", "air_purifier", "demo", device_id=device_entry.id
|
||||
)
|
||||
|
||||
hass.states.async_set(
|
||||
humidity_sensor.entity_id,
|
||||
"42",
|
||||
{
|
||||
ATTR_DEVICE_CLASS: SensorDeviceClass.HUMIDITY,
|
||||
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
|
||||
},
|
||||
)
|
||||
hass.states.async_set(
|
||||
pm25_sensor.entity_id,
|
||||
8,
|
||||
{
|
||||
ATTR_DEVICE_CLASS: SensorDeviceClass.PM25,
|
||||
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
},
|
||||
)
|
||||
hass.states.async_set(
|
||||
temperature_sensor.entity_id,
|
||||
22,
|
||||
{
|
||||
ATTR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE,
|
||||
ATTR_UNIT_OF_MEASUREMENT: UnitOfTemperature.CELSIUS,
|
||||
},
|
||||
)
|
||||
hass.states.async_set(air_purifier.entity_id, STATE_ON)
|
||||
|
||||
with (
|
||||
patch.object(homekit.bridge, "add_accessory"),
|
||||
patch(f"{PATH_HOMEKIT}.async_show_setup_message"),
|
||||
patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc,
|
||||
patch("pyhap.accessory_driver.AccessoryDriver.async_start"),
|
||||
):
|
||||
await homekit.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_get_acc.assert_called_with(
|
||||
hass,
|
||||
ANY,
|
||||
ANY,
|
||||
ANY,
|
||||
{
|
||||
"manufacturer": "Home Assistant",
|
||||
"model": "Smart Air Purifier",
|
||||
"platform": "air_purifier",
|
||||
"sw_version": "0.16.1",
|
||||
"type": TYPE_AIR_PURIFIER,
|
||||
"linked_humidity_sensor": "sensor.air_purifier_humidity_sensor",
|
||||
"linked_pm25_sensor": "sensor.air_purifier_pm25_sensor",
|
||||
"linked_temperature_sensor": "sensor.air_purifier_temperature_sensor",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_async_zeroconf")
|
||||
async def test_reload(hass: HomeAssistant) -> None:
|
||||
"""Test we can reload from yaml."""
|
||||
|
||||
Reference in New Issue
Block a user