From a2c9aa766266730a410169399990a8e7c80db6d3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 24 Oct 2024 05:49:40 -1000 Subject: [PATCH] Add Meter Pro support to SwitchBot (#128991) --- .../components/switchbot/__init__.py | 1 + homeassistant/components/switchbot/const.py | 3 ++ homeassistant/components/switchbot/sensor.py | 7 +++ tests/components/switchbot/__init__.py | 25 ++++++++++ tests/components/switchbot/test_sensor.py | 48 ++++++++++++++++++- 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/switchbot/__init__.py b/homeassistant/components/switchbot/__init__.py index 75845d3f3ce..c2b4b2ad736 100644 --- a/homeassistant/components/switchbot/__init__.py +++ b/homeassistant/components/switchbot/__init__.py @@ -41,6 +41,7 @@ PLATFORMS_BY_TYPE = { Platform.SENSOR, ], SupportedModels.HYGROMETER.value: [Platform.SENSOR], + SupportedModels.HYGROMETER_CO2.value: [Platform.SENSOR], SupportedModels.CONTACT.value: [Platform.BINARY_SENSOR, Platform.SENSOR], SupportedModels.MOTION.value: [Platform.BINARY_SENSOR, Platform.SENSOR], SupportedModels.HUMIDIFIER.value: [Platform.HUMIDIFIER, Platform.SENSOR], diff --git a/homeassistant/components/switchbot/const.py b/homeassistant/components/switchbot/const.py index bd727edfea4..19b264bd46f 100644 --- a/homeassistant/components/switchbot/const.py +++ b/homeassistant/components/switchbot/const.py @@ -20,6 +20,7 @@ class SupportedModels(StrEnum): CEILING_LIGHT = "ceiling_light" CURTAIN = "curtain" HYGROMETER = "hygrometer" + HYGROMETER_CO2 = "hygrometer_co2" LIGHT_STRIP = "light_strip" CONTACT = "contact" PLUG = "plug" @@ -48,6 +49,8 @@ CONNECTABLE_SUPPORTED_MODEL_TYPES = { NON_CONNECTABLE_SUPPORTED_MODEL_TYPES = { SwitchbotModel.METER: SupportedModels.HYGROMETER, SwitchbotModel.IO_METER: SupportedModels.HYGROMETER, + SwitchbotModel.METER_PRO: SupportedModels.HYGROMETER, + SwitchbotModel.METER_PRO_C: SupportedModels.HYGROMETER_CO2, SwitchbotModel.CONTACT_SENSOR: SupportedModels.CONTACT, SwitchbotModel.MOTION_SENSOR: SupportedModels.MOTION, } diff --git a/homeassistant/components/switchbot/sensor.py b/homeassistant/components/switchbot/sensor.py index e696f21e082..fd3de3e31e9 100644 --- a/homeassistant/components/switchbot/sensor.py +++ b/homeassistant/components/switchbot/sensor.py @@ -10,6 +10,7 @@ from homeassistant.components.sensor import ( SensorStateClass, ) from homeassistant.const import ( + CONCENTRATION_PARTS_PER_MILLION, PERCENTAGE, SIGNAL_STRENGTH_DECIBELS_MILLIWATT, EntityCategory, @@ -50,6 +51,12 @@ SENSOR_TYPES: dict[str, SensorEntityDescription] = { state_class=SensorStateClass.MEASUREMENT, entity_category=EntityCategory.DIAGNOSTIC, ), + "co2": SensorEntityDescription( + key="co2", + native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.CO2, + ), "lightLevel": SensorEntityDescription( key="lightLevel", translation_key="light_level", diff --git a/tests/components/switchbot/__init__.py b/tests/components/switchbot/__init__.py index b2a8445546e..bd3985ff062 100644 --- a/tests/components/switchbot/__init__.py +++ b/tests/components/switchbot/__init__.py @@ -205,3 +205,28 @@ NOT_SWITCHBOT_INFO = BluetoothServiceInfoBleak( connectable=True, tx_power=-127, ) + + +WOMETERTHPC_SERVICE_INFO = BluetoothServiceInfoBleak( + name="WoTHPc", + manufacturer_data={ + 2409: b"\xb0\xe9\xfeT2\x15\xb7\xe4\x07\x9b\xa4\x007\x02\xd5\x00" + }, + service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"5\x00d"}, + service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"], + address="AA:BB:CC:DD:EE:AA", + rssi=-60, + source="local", + advertisement=generate_advertisement_data( + local_name="WoTHPc", + manufacturer_data={ + 2409: b"\xb0\xe9\xfeT2\x15\xb7\xe4\x07\x9b\xa4\x007\x02\xd5\x00" + }, + service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"5\x00d"}, + service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"], + ), + device=generate_ble_device("AA:BB:CC:DD:EE:AA", "WoTHPc"), + time=0, + connectable=True, + tx_power=-127, +) diff --git a/tests/components/switchbot/test_sensor.py b/tests/components/switchbot/test_sensor.py index 030a477596c..3adeaef936c 100644 --- a/tests/components/switchbot/test_sensor.py +++ b/tests/components/switchbot/test_sensor.py @@ -15,7 +15,7 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component -from . import WOHAND_SERVICE_INFO +from . import WOHAND_SERVICE_INFO, WOMETERTHPC_SERVICE_INFO from tests.common import MockConfigEntry from tests.components.bluetooth import inject_bluetooth_service_info @@ -59,3 +59,49 @@ async def test_sensors(hass: HomeAssistant) -> None: assert await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default") +async def test_co2_sensor(hass: HomeAssistant) -> None: + """Test setting up creates the co2 sensor for a WoTHPc.""" + await async_setup_component(hass, DOMAIN, {}) + inject_bluetooth_service_info(hass, WOMETERTHPC_SERVICE_INFO) + + entry = MockConfigEntry( + domain=DOMAIN, + data={ + CONF_ADDRESS: "AA:BB:CC:DD:EE:AA", + CONF_NAME: "test-name", + CONF_PASSWORD: "test-password", + CONF_SENSOR_TYPE: "hygrometer_co2", + }, + unique_id="aabbccddeeaa", + ) + entry.add_to_hass(hass) + + assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert len(hass.states.async_all("sensor")) == 5 + + battery_sensor = hass.states.get("sensor.test_name_battery") + battery_sensor_attrs = battery_sensor.attributes + assert battery_sensor.state == "100" + assert battery_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Battery" + assert battery_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "%" + assert battery_sensor_attrs[ATTR_STATE_CLASS] == "measurement" + + rssi_sensor = hass.states.get("sensor.test_name_bluetooth_signal") + rssi_sensor_attrs = rssi_sensor.attributes + assert rssi_sensor.state == "-60" + assert rssi_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Bluetooth signal" + assert rssi_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "dBm" + + co2_sensor = hass.states.get("sensor.test_name_carbon_dioxide") + co2_sensor_attrs = co2_sensor.attributes + assert co2_sensor.state == "725" + assert co2_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Carbon dioxide" + assert co2_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "ppm" + + assert await hass.config_entries.async_unload(entry.entry_id) + await hass.async_block_till_done()