mirror of
https://github.com/home-assistant/core.git
synced 2026-05-15 04:51:20 +01:00
c6a5e49c8f
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1176 lines
47 KiB
Python
1176 lines
47 KiB
Python
"""Test the switchbot sensors."""
|
|
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
import pytest
|
|
from switchbot import SwitchBotAdvertisement, SwitchbotModel
|
|
|
|
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
|
|
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
|
from homeassistant.components.switchbot.const import (
|
|
CONF_ENCRYPTION_KEY,
|
|
CONF_KEY_ID,
|
|
DOMAIN,
|
|
)
|
|
from homeassistant.const import (
|
|
ATTR_DEVICE_CLASS,
|
|
ATTR_FRIENDLY_NAME,
|
|
ATTR_UNIT_OF_MEASUREMENT,
|
|
CONF_ADDRESS,
|
|
CONF_NAME,
|
|
CONF_PASSWORD,
|
|
CONF_SENSOR_TYPE,
|
|
STATE_OFF,
|
|
STATE_ON,
|
|
STATE_UNKNOWN,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
from . import (
|
|
AIR_PURIFIER_TABLE_US_SERVICE_INFO,
|
|
CIRCULATOR_FAN_SERVICE_INFO,
|
|
CLIMATE_PANEL_SERVICE_INFO,
|
|
EVAPORATIVE_HUMIDIFIER_SERVICE_INFO,
|
|
HUB3_SERVICE_INFO,
|
|
HUBMINI_MATTER_SERVICE_INFO,
|
|
KEYPAD_VISION_INFO,
|
|
KEYPAD_VISION_PRO_INFO,
|
|
LEAK_SERVICE_INFO,
|
|
PLUG_MINI_EU_SERVICE_INFO,
|
|
PRESENCE_SENSOR_SERVICE_INFO,
|
|
RELAY_SWITCH_2PM_SERVICE_INFO,
|
|
REMOTE_SERVICE_INFO,
|
|
WOHAND_SERVICE_INFO,
|
|
WOHUB2_SERVICE_INFO,
|
|
WOMETERTHPC_SERVICE_INFO,
|
|
WORELAY_SWITCH_1PM_SERVICE_INFO,
|
|
)
|
|
|
|
from tests.common import MockConfigEntry
|
|
from tests.components.bluetooth import inject_bluetooth_service_info
|
|
|
|
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_sensors(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the sensors."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, WOHAND_SERVICE_INFO)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
|
CONF_NAME: "test-name",
|
|
CONF_PASSWORD: "test-password",
|
|
CONF_SENSOR_TYPE: "bot",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
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")) == 2
|
|
|
|
battery_sensor = hass.states.get("sensor.test_name_battery")
|
|
battery_sensor_attrs = battery_sensor.attributes
|
|
assert battery_sensor.state == "89"
|
|
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"
|
|
|
|
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:FF",
|
|
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()
|
|
|
|
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_relay_switch_1pm_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the relay switch 1PM sensor."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, WORELAY_SWITCH_1PM_SERVICE_INFO)
|
|
|
|
with patch(
|
|
"homeassistant.components.switchbot.switch.switchbot.SwitchbotRelaySwitch.get_basic_info",
|
|
new=AsyncMock(
|
|
return_value={
|
|
"power": 4.9,
|
|
"current": 0.02,
|
|
"voltage": 25,
|
|
"energy": 0.2,
|
|
}
|
|
),
|
|
):
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "relay_switch_1pm",
|
|
CONF_KEY_ID: "ff",
|
|
CONF_ENCRYPTION_KEY: "ffffffffffffffffffffffffffffffff",
|
|
},
|
|
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
|
|
|
|
power_sensor = hass.states.get("sensor.test_name_power")
|
|
power_sensor_attrs = power_sensor.attributes
|
|
assert power_sensor.state == "4.9"
|
|
assert power_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Power"
|
|
assert power_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "W"
|
|
assert power_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
voltage_sensor = hass.states.get("sensor.test_name_voltage")
|
|
voltage_sensor_attrs = voltage_sensor.attributes
|
|
assert voltage_sensor.state == "25"
|
|
assert voltage_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Voltage"
|
|
assert voltage_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "V"
|
|
assert voltage_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
current_sensor = hass.states.get("sensor.test_name_current")
|
|
current_sensor_attrs = current_sensor.attributes
|
|
assert current_sensor.state == "0.02"
|
|
assert current_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Current"
|
|
assert current_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "A"
|
|
assert current_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
energy_sensor = hass.states.get("sensor.test_name_energy")
|
|
energy_sensor_attrs = energy_sensor.attributes
|
|
assert energy_sensor.state == "0.2"
|
|
assert energy_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Energy"
|
|
assert energy_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "kWh"
|
|
assert energy_sensor_attrs[ATTR_STATE_CLASS] == "total_increasing"
|
|
|
|
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"
|
|
assert rssi_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
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_leak_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up the leak detector."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, LEAK_SERVICE_INFO)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "leak",
|
|
},
|
|
unique_id="aabbccddeeaa",
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
battery_sensor = hass.states.get("sensor.test_name_battery")
|
|
battery_sensor_attrs = battery_sensor.attributes
|
|
assert battery_sensor.state == "86"
|
|
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"
|
|
|
|
leak_sensor = hass.states.get("binary_sensor.test_name")
|
|
leak_sensor_attrs = leak_sensor.attributes
|
|
assert leak_sensor.state == "off"
|
|
assert leak_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name"
|
|
|
|
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_remote(hass: HomeAssistant) -> None:
|
|
"""Test setting up the remote sensor."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, REMOTE_SERVICE_INFO)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "remote",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
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")) == 2
|
|
|
|
battery_sensor = hass.states.get("sensor.test_name_battery")
|
|
battery_sensor_attrs = battery_sensor.attributes
|
|
assert battery_sensor.state == "86"
|
|
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"
|
|
|
|
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_hub2_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the sensor for WoHub2."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, WOHUB2_SERVICE_INFO)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "hub2",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
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
|
|
|
|
temperature_sensor = hass.states.get("sensor.test_name_temperature")
|
|
temperature_sensor_attrs = temperature_sensor.attributes
|
|
assert temperature_sensor.state == "26.4"
|
|
assert temperature_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Temperature"
|
|
assert temperature_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "°C"
|
|
assert temperature_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
humidity_sensor = hass.states.get("sensor.test_name_humidity")
|
|
humidity_sensor_attrs = humidity_sensor.attributes
|
|
assert humidity_sensor.state == "44"
|
|
assert humidity_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Humidity"
|
|
assert humidity_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "%"
|
|
assert humidity_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
light_level_sensor = hass.states.get("sensor.test_name_light_level")
|
|
light_level_sensor_attrs = light_level_sensor.attributes
|
|
assert light_level_sensor.state == "4"
|
|
assert light_level_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Light level"
|
|
|
|
illuminance_sensor = hass.states.get("sensor.test_name_illuminance")
|
|
illuminance_sensor_attrs = illuminance_sensor.attributes
|
|
assert illuminance_sensor.state == "30"
|
|
assert illuminance_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Illuminance"
|
|
assert illuminance_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "lx"
|
|
|
|
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"
|
|
|
|
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_hubmini_matter_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the sensor for HubMini Matter."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, HUBMINI_MATTER_SERVICE_INFO)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "hubmini_matter",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
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")) == 3
|
|
|
|
temperature_sensor = hass.states.get("sensor.test_name_temperature")
|
|
temperature_sensor_attrs = temperature_sensor.attributes
|
|
assert temperature_sensor.state == "24.1"
|
|
assert temperature_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Temperature"
|
|
assert temperature_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "°C"
|
|
assert temperature_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
humidity_sensor = hass.states.get("sensor.test_name_humidity")
|
|
humidity_sensor_attrs = humidity_sensor.attributes
|
|
assert humidity_sensor.state == "53"
|
|
assert humidity_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Humidity"
|
|
assert humidity_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "%"
|
|
assert humidity_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"
|
|
|
|
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_fan_sensors(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the sensors."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, CIRCULATOR_FAN_SERVICE_INFO)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
|
CONF_NAME: "test-name",
|
|
CONF_PASSWORD: "test-password",
|
|
CONF_SENSOR_TYPE: "circulator_fan",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
with patch(
|
|
"homeassistant.components.switchbot.fan.switchbot.SwitchbotFan.update",
|
|
return_value=True,
|
|
):
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(hass.states.async_all("sensor")) == 2
|
|
|
|
battery_sensor = hass.states.get("sensor.test_name_battery")
|
|
battery_sensor_attrs = battery_sensor.attributes
|
|
assert battery_sensor.state == "82"
|
|
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"
|
|
|
|
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_hub3_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the sensor for Hub3."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, HUB3_SERVICE_INFO)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "hub3",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
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
|
|
|
|
temperature_sensor = hass.states.get("sensor.test_name_temperature")
|
|
temperature_sensor_attrs = temperature_sensor.attributes
|
|
assert temperature_sensor.state == "25.3"
|
|
assert temperature_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Temperature"
|
|
assert temperature_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "°C"
|
|
assert temperature_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
humidity_sensor = hass.states.get("sensor.test_name_humidity")
|
|
humidity_sensor_attrs = humidity_sensor.attributes
|
|
assert humidity_sensor.state == "52"
|
|
assert humidity_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Humidity"
|
|
assert humidity_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "%"
|
|
assert humidity_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"
|
|
|
|
light_level_sensor = hass.states.get("sensor.test_name_light_level")
|
|
light_level_sensor_attrs = light_level_sensor.attributes
|
|
assert light_level_sensor.state == "3"
|
|
assert light_level_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Light level"
|
|
assert light_level_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
illuminance_sensor = hass.states.get("sensor.test_name_illuminance")
|
|
illuminance_sensor_attrs = illuminance_sensor.attributes
|
|
assert illuminance_sensor.state == "90"
|
|
assert illuminance_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Illuminance"
|
|
assert illuminance_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "lx"
|
|
assert illuminance_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
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_evaporative_humidifier_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the sensor for evaporative humidifier."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, EVAPORATIVE_HUMIDIFIER_SERVICE_INFO)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "evaporative_humidifier",
|
|
CONF_KEY_ID: "ff",
|
|
CONF_ENCRYPTION_KEY: "ffffffffffffffffffffffffffffffff",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
with patch(
|
|
"homeassistant.components.switchbot.humidifier.switchbot.SwitchbotEvaporativeHumidifier.update",
|
|
return_value=True,
|
|
):
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(hass.states.async_all("sensor")) == 4
|
|
|
|
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"
|
|
|
|
humidity_sensor = hass.states.get("sensor.test_name_humidity")
|
|
humidity_sensor_attrs = humidity_sensor.attributes
|
|
assert humidity_sensor.state == "53"
|
|
assert humidity_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Humidity"
|
|
assert humidity_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "%"
|
|
assert humidity_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
temperature_sensor = hass.states.get("sensor.test_name_temperature")
|
|
temperature_sensor_attrs = temperature_sensor.attributes
|
|
assert temperature_sensor.state == "25.1"
|
|
assert temperature_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Temperature"
|
|
assert temperature_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "°C"
|
|
assert temperature_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
water_level_sensor = hass.states.get("sensor.test_name_water_level")
|
|
water_level_sensor_attrs = water_level_sensor.attributes
|
|
assert water_level_sensor.state == "medium"
|
|
assert water_level_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Water level"
|
|
assert water_level_sensor_attrs[ATTR_DEVICE_CLASS] == "enum"
|
|
|
|
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_plug_mini_eu_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the plug mini eu sensor."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, PLUG_MINI_EU_SERVICE_INFO)
|
|
|
|
with patch(
|
|
"homeassistant.components.switchbot.switch.switchbot.SwitchbotRelaySwitch.get_basic_info",
|
|
new=AsyncMock(
|
|
return_value={
|
|
"power": 500,
|
|
"current": 0.5,
|
|
"voltage": 230,
|
|
"energy": 0.4,
|
|
}
|
|
),
|
|
):
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "plug_mini_eu",
|
|
CONF_KEY_ID: "ff",
|
|
CONF_ENCRYPTION_KEY: "ffffffffffffffffffffffffffffffff",
|
|
},
|
|
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
|
|
|
|
power_sensor = hass.states.get("sensor.test_name_power")
|
|
power_sensor_attrs = power_sensor.attributes
|
|
assert power_sensor.state == "500"
|
|
assert power_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Power"
|
|
assert power_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "W"
|
|
assert power_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
voltage_sensor = hass.states.get("sensor.test_name_voltage")
|
|
voltage_sensor_attrs = voltage_sensor.attributes
|
|
assert voltage_sensor.state == "230"
|
|
assert voltage_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Voltage"
|
|
assert voltage_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "V"
|
|
assert voltage_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
current_sensor = hass.states.get("sensor.test_name_current")
|
|
current_sensor_attrs = current_sensor.attributes
|
|
assert current_sensor.state == "0.5"
|
|
assert current_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Current"
|
|
assert current_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "A"
|
|
assert current_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
energy_sensor = hass.states.get("sensor.test_name_energy")
|
|
energy_sensor_attrs = energy_sensor.attributes
|
|
assert energy_sensor.state == "0.4"
|
|
assert energy_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Energy"
|
|
assert energy_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "kWh"
|
|
assert energy_sensor_attrs[ATTR_STATE_CLASS] == "total_increasing"
|
|
|
|
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"
|
|
assert rssi_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
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_relay_switch_2pm_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the relay switch 2PM sensor."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, RELAY_SWITCH_2PM_SERVICE_INFO)
|
|
|
|
with patch(
|
|
"homeassistant.components.switchbot.switch.switchbot.SwitchbotRelaySwitch2PM.get_basic_info",
|
|
new=AsyncMock(
|
|
return_value={
|
|
1: {
|
|
"power": 4.9,
|
|
"current": 0.1,
|
|
"voltage": 25,
|
|
"energy": 0.2,
|
|
},
|
|
2: {
|
|
"power": 7.9,
|
|
"current": 0.6,
|
|
"voltage": 25,
|
|
"energy": 2.5,
|
|
},
|
|
}
|
|
),
|
|
):
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "relay_switch_2pm",
|
|
CONF_KEY_ID: "ff",
|
|
CONF_ENCRYPTION_KEY: "ffffffffffffffffffffffffffffffff",
|
|
},
|
|
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")) == 9
|
|
|
|
power_sensor_1 = hass.states.get("sensor.test_name_channel_1_power")
|
|
power_sensor_attrs = power_sensor_1.attributes
|
|
assert power_sensor_1.state == "4.9"
|
|
assert power_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Channel 1 Power"
|
|
assert power_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "W"
|
|
assert power_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
voltage_sensor_1 = hass.states.get("sensor.test_name_channel_1_voltage")
|
|
voltage_sensor_1_attrs = voltage_sensor_1.attributes
|
|
assert voltage_sensor_1.state == "25"
|
|
assert voltage_sensor_1_attrs[ATTR_FRIENDLY_NAME] == "test-name Channel 1 Voltage"
|
|
assert voltage_sensor_1_attrs[ATTR_UNIT_OF_MEASUREMENT] == "V"
|
|
assert voltage_sensor_1_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
current_sensor_1 = hass.states.get("sensor.test_name_channel_1_current")
|
|
current_sensor_1_attrs = current_sensor_1.attributes
|
|
assert current_sensor_1.state == "0.1"
|
|
assert current_sensor_1_attrs[ATTR_FRIENDLY_NAME] == "test-name Channel 1 Current"
|
|
assert current_sensor_1_attrs[ATTR_UNIT_OF_MEASUREMENT] == "A"
|
|
assert current_sensor_1_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
energy_sensor_1 = hass.states.get("sensor.test_name_channel_1_energy")
|
|
energy_sensor_1_attrs = energy_sensor_1.attributes
|
|
assert energy_sensor_1.state == "0.2"
|
|
assert energy_sensor_1_attrs[ATTR_FRIENDLY_NAME] == "test-name Channel 1 Energy"
|
|
assert energy_sensor_1_attrs[ATTR_UNIT_OF_MEASUREMENT] == "kWh"
|
|
assert energy_sensor_1_attrs[ATTR_STATE_CLASS] == "total_increasing"
|
|
|
|
power_sensor_2 = hass.states.get("sensor.test_name_channel_2_power")
|
|
power_sensor_2_attrs = power_sensor_2.attributes
|
|
assert power_sensor_2.state == "7.9"
|
|
assert power_sensor_2_attrs[ATTR_FRIENDLY_NAME] == "test-name Channel 2 Power"
|
|
assert power_sensor_2_attrs[ATTR_UNIT_OF_MEASUREMENT] == "W"
|
|
assert power_sensor_2_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
voltage_sensor_2 = hass.states.get("sensor.test_name_channel_2_voltage")
|
|
voltage_sensor_2_attrs = voltage_sensor_2.attributes
|
|
assert voltage_sensor_2.state == "25"
|
|
assert voltage_sensor_2_attrs[ATTR_FRIENDLY_NAME] == "test-name Channel 2 Voltage"
|
|
assert voltage_sensor_2_attrs[ATTR_UNIT_OF_MEASUREMENT] == "V"
|
|
assert voltage_sensor_2_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
current_sensor_2 = hass.states.get("sensor.test_name_channel_2_current")
|
|
current_sensor_2_attrs = current_sensor_2.attributes
|
|
assert current_sensor_2.state == "0.6"
|
|
assert current_sensor_2_attrs[ATTR_FRIENDLY_NAME] == "test-name Channel 2 Current"
|
|
assert current_sensor_2_attrs[ATTR_UNIT_OF_MEASUREMENT] == "A"
|
|
assert current_sensor_2_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
energy_sensor_2 = hass.states.get("sensor.test_name_channel_2_energy")
|
|
energy_sensor_2_attrs = energy_sensor_2.attributes
|
|
assert energy_sensor_2.state == "2.5"
|
|
assert energy_sensor_2_attrs[ATTR_FRIENDLY_NAME] == "test-name Channel 2 Energy"
|
|
assert energy_sensor_2_attrs[ATTR_UNIT_OF_MEASUREMENT] == "kWh"
|
|
assert energy_sensor_2_attrs[ATTR_STATE_CLASS] == "total_increasing"
|
|
|
|
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"
|
|
assert rssi_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
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_climate_panel_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the sensor for Climate Panel."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, CLIMATE_PANEL_SERVICE_INFO)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "climate_panel",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
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")) == 4
|
|
assert len(hass.states.async_all("binary_sensor")) == 2
|
|
|
|
temperature_sensor = hass.states.get("sensor.test_name_temperature")
|
|
temperature_sensor_attrs = temperature_sensor.attributes
|
|
assert temperature_sensor.state == "26.6"
|
|
assert temperature_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Temperature"
|
|
assert temperature_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "°C"
|
|
assert temperature_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
humidity_sensor = hass.states.get("sensor.test_name_humidity")
|
|
humidity_sensor_attrs = humidity_sensor.attributes
|
|
assert humidity_sensor.state == "44"
|
|
assert humidity_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Humidity"
|
|
assert humidity_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "%"
|
|
assert humidity_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"
|
|
|
|
battery_sensor = hass.states.get("sensor.test_name_battery")
|
|
battery_sensor_attrs = battery_sensor.attributes
|
|
assert battery_sensor.state == "95"
|
|
assert battery_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Battery"
|
|
assert battery_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
light_sensor = hass.states.get("binary_sensor.test_name_light")
|
|
light_sensor_attrs = light_sensor.attributes
|
|
assert light_sensor.state == STATE_ON
|
|
assert light_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Light"
|
|
|
|
motion_sensor = hass.states.get("binary_sensor.test_name_motion")
|
|
motion_sensor_attrs = motion_sensor.attributes
|
|
assert motion_sensor.state == STATE_ON
|
|
assert motion_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Motion"
|
|
|
|
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_presence_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the sensors for Presence Sensor."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, PRESENCE_SENSOR_SERVICE_INFO)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "presence_sensor",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
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")) == 4
|
|
assert len(hass.states.async_all("binary_sensor")) == 1
|
|
|
|
battery_sensor = hass.states.get("sensor.test_name_battery")
|
|
battery_sensor_attrs = battery_sensor.attributes
|
|
assert battery_sensor
|
|
assert battery_sensor.state == "100"
|
|
assert battery_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Battery"
|
|
assert battery_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
battery_range_sensor = hass.states.get("sensor.test_name_battery_range")
|
|
assert battery_range_sensor is not None
|
|
assert battery_range_sensor.state == "high"
|
|
assert (
|
|
battery_range_sensor.attributes[ATTR_FRIENDLY_NAME] == "test-name Battery range"
|
|
)
|
|
|
|
light_level_sensor = hass.states.get("sensor.test_name_light_level")
|
|
light_level_sensor_attrs = light_level_sensor.attributes
|
|
assert light_level_sensor
|
|
assert light_level_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Light level"
|
|
|
|
rssi_sensor = hass.states.get("sensor.test_name_bluetooth_signal")
|
|
rssi_sensor_attrs = rssi_sensor.attributes
|
|
assert rssi_sensor
|
|
assert rssi_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Bluetooth signal"
|
|
assert rssi_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "dBm"
|
|
|
|
occupancy_sensor = hass.states.get("binary_sensor.test_name_occupancy")
|
|
occupancy_sensor_attrs = occupancy_sensor.attributes
|
|
assert occupancy_sensor
|
|
assert occupancy_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Occupancy"
|
|
|
|
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_presence_sensor_without_battery(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the sensors for Presence Sensor without battery."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, PRESENCE_SENSOR_SERVICE_INFO)
|
|
|
|
with patch(
|
|
"homeassistant.components.switchbot.sensor.switchbot.parse_advertisement_data",
|
|
return_value=SwitchBotAdvertisement(
|
|
address="AA:BB:CC:DD:EE:FF",
|
|
data={
|
|
"rawAdvData": b"\x00 d\x00\x10\xcc\xc8",
|
|
"data": {
|
|
"sequence_number": 190,
|
|
"adaptive_state": True,
|
|
"motion_detected": True,
|
|
"battery_range": ">=60%",
|
|
"trigger_flag": 0,
|
|
"led_state": True,
|
|
"lightLevel": 2,
|
|
},
|
|
"model": b"\x00\x10\xcc\xc8",
|
|
"isEncrypted": False,
|
|
"modelFriendlyName": "Presence Sensor",
|
|
"modelName": SwitchbotModel.PRESENCE_SENSOR,
|
|
},
|
|
device=PRESENCE_SENSOR_SERVICE_INFO.device,
|
|
rssi=PRESENCE_SENSOR_SERVICE_INFO.rssi,
|
|
active=True,
|
|
),
|
|
):
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "presence_sensor",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
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")) == 3
|
|
assert len(hass.states.async_all("binary_sensor")) == 1
|
|
|
|
battery_range_sensor = hass.states.get("sensor.test_name_battery_range")
|
|
assert battery_range_sensor is not None
|
|
br_sensor_attrs = battery_range_sensor.attributes
|
|
assert battery_range_sensor.state == "high"
|
|
assert br_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Battery range"
|
|
|
|
light_level_sensor = hass.states.get("sensor.test_name_light_level")
|
|
light_level_sensor_attrs = light_level_sensor.attributes
|
|
assert light_level_sensor
|
|
assert light_level_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Light level"
|
|
|
|
rssi_sensor = hass.states.get("sensor.test_name_bluetooth_signal")
|
|
rssi_sensor_attrs = rssi_sensor.attributes
|
|
assert rssi_sensor
|
|
assert rssi_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Bluetooth signal"
|
|
assert rssi_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "dBm"
|
|
|
|
occupancy_sensor = hass.states.get("binary_sensor.test_name_occupancy")
|
|
occupancy_sensor_attrs = occupancy_sensor.attributes
|
|
assert occupancy_sensor
|
|
assert occupancy_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Occupancy"
|
|
|
|
assert await hass.config_entries.async_unload(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
@pytest.mark.parametrize(
|
|
("raw_battery_range", "expected_state"),
|
|
[
|
|
("<10%", "critical"),
|
|
("10-19%", "low"),
|
|
("20-59%", "medium"),
|
|
(">=60%", "high"),
|
|
],
|
|
)
|
|
async def test_presence_sensor_battery_range_mapping(
|
|
hass: HomeAssistant,
|
|
raw_battery_range: str,
|
|
expected_state: str,
|
|
) -> None:
|
|
"""Test battery_range value mapping covers all four states."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, PRESENCE_SENSOR_SERVICE_INFO)
|
|
|
|
with patch(
|
|
"homeassistant.components.switchbot.sensor.switchbot.parse_advertisement_data",
|
|
return_value=SwitchBotAdvertisement(
|
|
address="AA:BB:CC:DD:EE:FF",
|
|
data={
|
|
"rawAdvData": b"\x00 d\x00\x10\xcc\xc8",
|
|
"data": {
|
|
"sequence_number": 190,
|
|
"adaptive_state": True,
|
|
"motion_detected": False,
|
|
"battery_range": raw_battery_range,
|
|
"trigger_flag": 0,
|
|
"led_state": True,
|
|
"lightLevel": 1,
|
|
},
|
|
"model": b"\x00\x10\xcc\xc8",
|
|
"isEncrypted": False,
|
|
"modelFriendlyName": "Presence Sensor",
|
|
"modelName": SwitchbotModel.PRESENCE_SENSOR,
|
|
},
|
|
device=PRESENCE_SENSOR_SERVICE_INFO.device,
|
|
rssi=PRESENCE_SENSOR_SERVICE_INFO.rssi,
|
|
active=True,
|
|
),
|
|
):
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "presence_sensor",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
battery_range_sensor = hass.states.get("sensor.test_name_battery_range")
|
|
assert battery_range_sensor is not None
|
|
assert battery_range_sensor.state == expected_state
|
|
|
|
assert await hass.config_entries.async_unload(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
@pytest.mark.parametrize(
|
|
("adv_info", "sensor_type", "charging_state"),
|
|
[
|
|
(KEYPAD_VISION_INFO, "keypad_vision", STATE_ON),
|
|
(KEYPAD_VISION_PRO_INFO, "keypad_vision_pro", STATE_OFF),
|
|
],
|
|
)
|
|
async def test_keypad_vision_sensor(
|
|
hass: HomeAssistant,
|
|
adv_info: BluetoothServiceInfoBleak,
|
|
sensor_type: str,
|
|
charging_state: str,
|
|
) -> None:
|
|
"""Test setting up creates the sensors for Keypad Vision (Pro)."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, adv_info)
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: sensor_type,
|
|
CONF_KEY_ID: "ff",
|
|
CONF_ENCRYPTION_KEY: "ffffffffffffffffffffffffffffffff",
|
|
},
|
|
unique_id="aabbccddeeff",
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
with patch(
|
|
"homeassistant.components.switchbot.sensor.switchbot.SwitchbotKeypadVision.update",
|
|
return_value=True,
|
|
):
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(hass.states.async_all("sensor")) == 2
|
|
assert len(hass.states.async_all("binary_sensor")) == 2
|
|
|
|
battery_sensor = hass.states.get("sensor.test_name_battery")
|
|
battery_sensor_attrs = battery_sensor.attributes
|
|
assert battery_sensor
|
|
assert battery_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Battery"
|
|
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
|
|
assert rssi_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Bluetooth signal"
|
|
assert rssi_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "dBm"
|
|
|
|
tamper_sensor = hass.states.get("binary_sensor.test_name_tamper")
|
|
tamper_sensor_attrs = tamper_sensor.attributes
|
|
assert tamper_sensor
|
|
assert tamper_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Tamper"
|
|
assert tamper_sensor.state == STATE_OFF
|
|
|
|
charging_sensor = hass.states.get("binary_sensor.test_name_charging")
|
|
charging_sensor_attrs = charging_sensor.attributes
|
|
assert charging_sensor
|
|
assert charging_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Charging"
|
|
assert charging_sensor.state == charging_state
|
|
|
|
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_air_purifier_sensor(hass: HomeAssistant) -> None:
|
|
"""Test setting up creates the air purifier sensor."""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, AIR_PURIFIER_TABLE_US_SERVICE_INFO)
|
|
|
|
with patch(
|
|
"homeassistant.components.switchbot.switch.switchbot.SwitchbotAirPurifier.get_basic_info",
|
|
new=AsyncMock(
|
|
return_value={
|
|
"pm25": 1,
|
|
"aqi_level": "excellent",
|
|
}
|
|
),
|
|
):
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "air_purifier_table_us",
|
|
CONF_KEY_ID: "ff",
|
|
CONF_ENCRYPTION_KEY: "ffffffffffffffffffffffffffffffff",
|
|
},
|
|
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 {state.entity_id for state in hass.states.async_all("sensor")} == {
|
|
"sensor.test_name_pm2_5",
|
|
"sensor.test_name_air_quality_level",
|
|
"sensor.test_name_bluetooth_signal",
|
|
}
|
|
|
|
pm25_sensor = hass.states.get("sensor.test_name_pm2_5")
|
|
pm25_sensor_attrs = pm25_sensor.attributes
|
|
assert pm25_sensor.state == "1"
|
|
assert pm25_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name PM2.5"
|
|
assert pm25_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "μg/m³"
|
|
assert pm25_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
|
|
|
aqi_sensor = hass.states.get("sensor.test_name_air_quality_level")
|
|
aqi_sensor_attrs = aqi_sensor.attributes
|
|
assert aqi_sensor.state == "excellent"
|
|
assert aqi_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Air quality level"
|
|
|
|
rssi_sensor = hass.states.get("sensor.test_name_bluetooth_signal")
|
|
rssi_sensor_attrs = rssi_sensor.attributes
|
|
assert rssi_sensor_attrs[ATTR_FRIENDLY_NAME] == "test-name Bluetooth signal"
|
|
assert rssi_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "dBm"
|
|
|
|
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_air_purifier_pm25_sensor_unknown_before_first_poll(
|
|
hass: HomeAssistant,
|
|
) -> None:
|
|
"""Test PM2.5 sensor shows unknown state when active poll has not yet returned data.
|
|
|
|
PM2.5 values are not included in BLE broadcast frames. They are only
|
|
available after an active BLE query (get_basic_info) triggered by the fan
|
|
entity's async_added_to_hass. The sensor entity is registered based on
|
|
device model capability so it is always present; if the initial poll fails
|
|
the entity state is STATE_UNKNOWN until a successful poll populates the value.
|
|
"""
|
|
await async_setup_component(hass, DOMAIN, {})
|
|
inject_bluetooth_service_info(hass, AIR_PURIFIER_TABLE_US_SERVICE_INFO)
|
|
|
|
with patch(
|
|
"homeassistant.components.switchbot.switch.switchbot.SwitchbotAirPurifier.get_basic_info",
|
|
new=AsyncMock(return_value=None),
|
|
):
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
|
CONF_NAME: "test-name",
|
|
CONF_SENSOR_TYPE: "air_purifier_table_us",
|
|
CONF_KEY_ID: "ff",
|
|
CONF_ENCRYPTION_KEY: "ffffffffffffffffffffffffffffffff",
|
|
},
|
|
unique_id="aabbccddeeab",
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
# PM2.5 entity must exist even when the initial poll returned no data.
|
|
pm25_sensor = hass.states.get("sensor.test_name_pm2_5")
|
|
assert pm25_sensor is not None
|
|
assert pm25_sensor.state == STATE_UNKNOWN
|
|
|
|
# aqi_level comes from broadcast data and is always available.
|
|
aqi_sensor = hass.states.get("sensor.test_name_air_quality_level")
|
|
assert aqi_sensor is not None
|
|
|
|
assert await hass.config_entries.async_unload(entry.entry_id)
|
|
await hass.async_block_till_done()
|