mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 10:17:09 +00:00
Merge branch 'dev' into whirlpool_sensor_door_remove
This commit is contained in:
commit
f07ee5d972
@ -29,6 +29,7 @@ PLATFORMS: list[Platform] = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.BUTTON,
|
||||
Platform.CLIMATE,
|
||||
Platform.FAN,
|
||||
Platform.LOCK,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
@ -51,6 +52,7 @@ class SwitchbotDevices:
|
||||
sensors: list[tuple[Device, SwitchBotCoordinator]] = field(default_factory=list)
|
||||
vacuums: list[tuple[Device, SwitchBotCoordinator]] = field(default_factory=list)
|
||||
locks: list[tuple[Device, SwitchBotCoordinator]] = field(default_factory=list)
|
||||
fans: list[tuple[Device, SwitchBotCoordinator]] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -96,7 +98,6 @@ async def make_switchbot_devices(
|
||||
for device in devices
|
||||
]
|
||||
)
|
||||
|
||||
return devices_data
|
||||
|
||||
|
||||
@ -177,6 +178,16 @@ async def make_device_data(
|
||||
else:
|
||||
devices_data.switches.append((device, coordinator))
|
||||
|
||||
if isinstance(device, Device) and device.device_type in [
|
||||
"Battery Circulator Fan",
|
||||
"Circulator Fan",
|
||||
]:
|
||||
coordinator = await coordinator_for_device(
|
||||
hass, entry, api, device, coordinators_by_id
|
||||
)
|
||||
devices_data.fans.append((device, coordinator))
|
||||
devices_data.sensors.append((device, coordinator))
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up SwitchBot via API from a config entry."""
|
||||
|
120
homeassistant/components/switchbot_cloud/fan.py
Normal file
120
homeassistant/components/switchbot_cloud/fan.py
Normal file
@ -0,0 +1,120 @@
|
||||
"""Support for the Switchbot Battery Circulator fan."""
|
||||
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from switchbot_api import (
|
||||
BatteryCirculatorFanCommands,
|
||||
BatteryCirculatorFanMode,
|
||||
CommonCommands,
|
||||
)
|
||||
|
||||
from homeassistant.components.fan import FanEntity, FanEntityFeature
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import SwitchbotCloudData
|
||||
from .const import DOMAIN
|
||||
from .entity import SwitchBotCloudEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up SwitchBot Cloud entry."""
|
||||
data: SwitchbotCloudData = hass.data[DOMAIN][config.entry_id]
|
||||
async_add_entities(
|
||||
SwitchBotCloudFan(data.api, device, coordinator)
|
||||
for device, coordinator in data.devices.fans
|
||||
)
|
||||
|
||||
|
||||
class SwitchBotCloudFan(SwitchBotCloudEntity, FanEntity):
|
||||
"""Representation of a SwitchBot Battery Circulator Fan."""
|
||||
|
||||
_attr_name = None
|
||||
|
||||
_attr_supported_features = (
|
||||
FanEntityFeature.SET_SPEED
|
||||
| FanEntityFeature.PRESET_MODE
|
||||
| FanEntityFeature.TURN_OFF
|
||||
| FanEntityFeature.TURN_ON
|
||||
)
|
||||
_attr_preset_modes = list(BatteryCirculatorFanMode)
|
||||
|
||||
_attr_is_on: bool | None = None
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool | None:
|
||||
"""Return true if the entity is on."""
|
||||
return self._attr_is_on
|
||||
|
||||
def _set_attributes(self) -> None:
|
||||
"""Set attributes from coordinator data."""
|
||||
if self.coordinator.data is None:
|
||||
return
|
||||
|
||||
power: str = self.coordinator.data["power"]
|
||||
mode: str = self.coordinator.data["mode"]
|
||||
fan_speed: str = self.coordinator.data["fanSpeed"]
|
||||
self._attr_is_on = power == "on"
|
||||
self._attr_preset_mode = mode
|
||||
self._attr_percentage = int(fan_speed)
|
||||
self._attr_supported_features = (
|
||||
FanEntityFeature.PRESET_MODE
|
||||
| FanEntityFeature.TURN_OFF
|
||||
| FanEntityFeature.TURN_ON
|
||||
)
|
||||
if self.is_on and self.preset_mode == BatteryCirculatorFanMode.DIRECT.value:
|
||||
self._attr_supported_features |= FanEntityFeature.SET_SPEED
|
||||
|
||||
async def async_turn_on(
|
||||
self,
|
||||
percentage: int | None = None,
|
||||
preset_mode: str | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Turn on the fan."""
|
||||
await self.send_api_command(CommonCommands.ON)
|
||||
await self.send_api_command(
|
||||
command=BatteryCirculatorFanCommands.SET_WIND_MODE,
|
||||
parameters=str(self.preset_mode),
|
||||
)
|
||||
if self.preset_mode == BatteryCirculatorFanMode.DIRECT.value:
|
||||
await self.send_api_command(
|
||||
command=BatteryCirculatorFanCommands.SET_WIND_SPEED,
|
||||
parameters=str(self.percentage),
|
||||
)
|
||||
await asyncio.sleep(5)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off the fan."""
|
||||
await self.send_api_command(CommonCommands.OFF)
|
||||
await asyncio.sleep(5)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def async_set_percentage(self, percentage: int) -> None:
|
||||
"""Set the speed of the fan, as a percentage."""
|
||||
await self.send_api_command(
|
||||
command=BatteryCirculatorFanCommands.SET_WIND_MODE,
|
||||
parameters=str(BatteryCirculatorFanMode.DIRECT.value),
|
||||
)
|
||||
await self.send_api_command(
|
||||
command=BatteryCirculatorFanCommands.SET_WIND_SPEED,
|
||||
parameters=str(percentage),
|
||||
)
|
||||
await asyncio.sleep(5)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set new preset mode."""
|
||||
await self.send_api_command(
|
||||
command=BatteryCirculatorFanCommands.SET_WIND_MODE,
|
||||
parameters=preset_mode,
|
||||
)
|
||||
await asyncio.sleep(5)
|
||||
await self.coordinator.async_request_refresh()
|
@ -91,6 +91,7 @@ CO2_DESCRIPTION = SensorEntityDescription(
|
||||
|
||||
SENSOR_DESCRIPTIONS_BY_DEVICE_TYPES = {
|
||||
"Bot": (BATTERY_DESCRIPTION,),
|
||||
"Battery Circulator Fan": (BATTERY_DESCRIPTION,),
|
||||
"Meter": (
|
||||
TEMPERATURE_DESCRIPTION,
|
||||
HUMIDITY_DESCRIPTION,
|
||||
|
@ -165,6 +165,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
hass.data[DOMAIN][entry.entry_id] = YoLinkHomeStore(
|
||||
yolink_home, device_coordinators
|
||||
)
|
||||
|
||||
# Clean up yolink devices which are not associated to the account anymore.
|
||||
device_registry = dr.async_get(hass)
|
||||
device_entries = dr.async_entries_for_config_entry(device_registry, entry.entry_id)
|
||||
for device_entry in device_entries:
|
||||
for identifier in device_entry.identifiers:
|
||||
if (
|
||||
identifier[0] == DOMAIN
|
||||
and device_coordinators.get(identifier[1]) is None
|
||||
):
|
||||
device_registry.async_update_device(
|
||||
device_entry.id, remove_config_entry_id=entry.entry_id
|
||||
)
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
async def async_yolink_unload(event) -> None:
|
||||
|
187
tests/components/switchbot_cloud/test_fan.py
Normal file
187
tests/components/switchbot_cloud/test_fan.py
Normal file
@ -0,0 +1,187 @@
|
||||
"""Test for the Switchbot Battery Circulator Fan."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from switchbot_api import Device, SwitchBotAPI
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
ATTR_PERCENTAGE,
|
||||
ATTR_PRESET_MODE,
|
||||
DOMAIN as FAN_DOMAIN,
|
||||
SERVICE_SET_PERCENTAGE,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
SERVICE_TURN_ON,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
SERVICE_TURN_OFF,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
STATE_UNKNOWN,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import configure_integration
|
||||
|
||||
|
||||
async def test_coordinator_data_is_none(
|
||||
hass: HomeAssistant, mock_list_devices, mock_get_status
|
||||
) -> None:
|
||||
"""Test coordinator data is none."""
|
||||
mock_list_devices.return_value = [
|
||||
Device(
|
||||
version="V1.0",
|
||||
deviceId="battery-fan-id-1",
|
||||
deviceName="battery-fan-1",
|
||||
deviceType="Battery Circulator Fan",
|
||||
hubDeviceId="test-hub-id",
|
||||
),
|
||||
]
|
||||
mock_get_status.side_effect = [
|
||||
None,
|
||||
]
|
||||
entry = await configure_integration(hass)
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
entity_id = "fan.battery_fan_1"
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state.state == STATE_UNKNOWN
|
||||
|
||||
|
||||
async def test_turn_on(hass: HomeAssistant, mock_list_devices, mock_get_status) -> None:
|
||||
"""Test turning on the fan."""
|
||||
mock_list_devices.return_value = [
|
||||
Device(
|
||||
version="V1.0",
|
||||
deviceId="battery-fan-id-1",
|
||||
deviceName="battery-fan-1",
|
||||
deviceType="Battery Circulator Fan",
|
||||
hubDeviceId="test-hub-id",
|
||||
),
|
||||
]
|
||||
mock_get_status.side_effect = [
|
||||
{"power": "off", "mode": "direct", "fanSpeed": "0"},
|
||||
{"power": "on", "mode": "direct", "fanSpeed": "0"},
|
||||
{"power": "on", "mode": "direct", "fanSpeed": "0"},
|
||||
]
|
||||
entry = await configure_integration(hass)
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
entity_id = "fan.battery_fan_1"
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
mock_send_command.assert_called()
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
|
||||
async def test_turn_off(
|
||||
hass: HomeAssistant, mock_list_devices, mock_get_status
|
||||
) -> None:
|
||||
"""Test turning off the fan."""
|
||||
mock_list_devices.return_value = [
|
||||
Device(
|
||||
version="V1.0",
|
||||
deviceId="battery-fan-id-1",
|
||||
deviceName="battery-fan-1",
|
||||
deviceType="Battery Circulator Fan",
|
||||
hubDeviceId="test-hub-id",
|
||||
),
|
||||
]
|
||||
mock_get_status.side_effect = [
|
||||
{"power": "on", "mode": "direct", "fanSpeed": "0"},
|
||||
{"power": "off", "mode": "direct", "fanSpeed": "0"},
|
||||
{"power": "off", "mode": "direct", "fanSpeed": "0"},
|
||||
]
|
||||
entry = await configure_integration(hass)
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
entity_id = "fan.battery_fan_1"
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state.state == STATE_ON
|
||||
|
||||
with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
mock_send_command.assert_called()
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
|
||||
async def test_set_percentage(
|
||||
hass: HomeAssistant, mock_list_devices, mock_get_status
|
||||
) -> None:
|
||||
"""Test set percentage."""
|
||||
mock_list_devices.return_value = [
|
||||
Device(
|
||||
version="V1.0",
|
||||
deviceId="battery-fan-id-1",
|
||||
deviceName="battery-fan-1",
|
||||
deviceType="Battery Circulator Fan",
|
||||
hubDeviceId="test-hub-id",
|
||||
),
|
||||
]
|
||||
mock_get_status.side_effect = [
|
||||
{"power": "on", "mode": "direct", "fanSpeed": "0"},
|
||||
{"power": "on", "mode": "direct", "fanSpeed": "0"},
|
||||
{"power": "off", "mode": "direct", "fanSpeed": "5"},
|
||||
]
|
||||
entry = await configure_integration(hass)
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
entity_id = "fan.battery_fan_1"
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state.state == STATE_ON
|
||||
|
||||
with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN,
|
||||
SERVICE_SET_PERCENTAGE,
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_PERCENTAGE: 5},
|
||||
blocking=True,
|
||||
)
|
||||
mock_send_command.assert_called()
|
||||
|
||||
|
||||
async def test_set_preset_mode(
|
||||
hass: HomeAssistant, mock_list_devices, mock_get_status
|
||||
) -> None:
|
||||
"""Test set preset mode."""
|
||||
mock_list_devices.return_value = [
|
||||
Device(
|
||||
version="V1.0",
|
||||
deviceId="battery-fan-id-1",
|
||||
deviceName="battery-fan-1",
|
||||
deviceType="Battery Circulator Fan",
|
||||
hubDeviceId="test-hub-id",
|
||||
),
|
||||
]
|
||||
mock_get_status.side_effect = [
|
||||
{"power": "on", "mode": "direct", "fanSpeed": "0"},
|
||||
{"power": "on", "mode": "direct", "fanSpeed": "0"},
|
||||
{"power": "on", "mode": "baby", "fanSpeed": "0"},
|
||||
]
|
||||
entry = await configure_integration(hass)
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
entity_id = "fan.battery_fan_1"
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state.state == STATE_ON
|
||||
|
||||
with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_PRESET_MODE: "baby"},
|
||||
blocking=True,
|
||||
)
|
||||
mock_send_command.assert_called_once()
|
@ -75,6 +75,14 @@ DEVICE_MOCKS = {
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.SENSOR,
|
||||
],
|
||||
"qxj_temp_humidity_external_probe": [
|
||||
# https://github.com/home-assistant/core/issues/136472
|
||||
Platform.SENSOR,
|
||||
],
|
||||
"qxj_weather_station": [
|
||||
# https://github.com/orgs/home-assistant/discussions/318
|
||||
Platform.SENSOR,
|
||||
],
|
||||
"rqbj_gas_sensor": [
|
||||
# https://github.com/orgs/home-assistant/discussions/100
|
||||
Platform.BINARY_SENSOR,
|
||||
|
@ -0,0 +1,65 @@
|
||||
{
|
||||
"endpoint": "https://apigw.tuyaeu.com",
|
||||
"terminal_id": "1708196692712PHOeqy",
|
||||
"mqtt_connected": true,
|
||||
"disabled_by": null,
|
||||
"disabled_polling": false,
|
||||
"id": "bff00f6abe0563b284t77p",
|
||||
"name": "Frysen",
|
||||
"category": "qxj",
|
||||
"product_id": "is2indt9nlth6esa",
|
||||
"product_name": "T & H Sensor with external probe",
|
||||
"online": true,
|
||||
"sub": false,
|
||||
"time_zone": "+01:00",
|
||||
"active_time": "2025-01-27T15:19:27+00:00",
|
||||
"create_time": "2025-01-27T15:19:27+00:00",
|
||||
"update_time": "2025-01-27T15:19:27+00:00",
|
||||
"function": {},
|
||||
"status_range": {
|
||||
"temp_current": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": -99,
|
||||
"max": 600,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"humidity_value": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "%",
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"scale": 0,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"battery_state": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["low", "middle", "high"]
|
||||
}
|
||||
},
|
||||
"temp_current_external": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": -400,
|
||||
"max": 1200,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"temp_current": 222,
|
||||
"humidity_value": 38,
|
||||
"battery_state": "high",
|
||||
"temp_current_external": -130
|
||||
},
|
||||
"set_up": false,
|
||||
"support_local": true
|
||||
}
|
412
tests/components/tuya/fixtures/qxj_weather_station.json
Normal file
412
tests/components/tuya/fixtures/qxj_weather_station.json
Normal file
@ -0,0 +1,412 @@
|
||||
{
|
||||
"endpoint": "https://apigw.tuyaeu.com",
|
||||
"terminal_id": "1751921699759JsVujI",
|
||||
"mqtt_connected": true,
|
||||
"disabled_by": null,
|
||||
"disabled_polling": false,
|
||||
"id": "bf84c743a84eb2c8abeurz",
|
||||
"name": "BR 7-in-1 WLAN Wetterstation Anthrazit",
|
||||
"category": "qxj",
|
||||
"product_id": "fsea1lat3vuktbt6",
|
||||
"product_name": "BR 7-in-1 WLAN Wetterstation Anthrazit",
|
||||
"online": true,
|
||||
"sub": false,
|
||||
"time_zone": "+02:00",
|
||||
"active_time": "2025-07-07T17:43:41+00:00",
|
||||
"create_time": "2025-07-07T17:43:41+00:00",
|
||||
"update_time": "2025-07-07T17:43:41+00:00",
|
||||
"function": {
|
||||
"temp_unit_convert": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["c", "f"]
|
||||
}
|
||||
},
|
||||
"windspeed_unit_convert": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["mph"]
|
||||
}
|
||||
},
|
||||
"pressure_unit_convert": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["hpa", "inhg", "mmhg"]
|
||||
}
|
||||
},
|
||||
"rain_unit_convert": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["mm", "inch"]
|
||||
}
|
||||
},
|
||||
"bright_unit_convert": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["lux", "fc", "wm2"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"status_range": {
|
||||
"temp_current": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": -400,
|
||||
"max": 600,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"humidity_value": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "%",
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"scale": 0,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"battery_state": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["low", "high"]
|
||||
}
|
||||
},
|
||||
"temp_unit_convert": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["c", "f"]
|
||||
}
|
||||
},
|
||||
"windspeed_unit_convert": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["mph"]
|
||||
}
|
||||
},
|
||||
"pressure_unit_convert": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["hpa", "inhg", "mmhg"]
|
||||
}
|
||||
},
|
||||
"rain_unit_convert": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["mm", "inch"]
|
||||
}
|
||||
},
|
||||
"bright_unit_convert": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["lux", "fc", "wm2"]
|
||||
}
|
||||
},
|
||||
"fault_type": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": [
|
||||
"normal",
|
||||
"ch1_offline",
|
||||
"ch2_offline",
|
||||
"ch3_offline",
|
||||
"offline"
|
||||
]
|
||||
}
|
||||
},
|
||||
"battery_status": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["low", "high"]
|
||||
}
|
||||
},
|
||||
"battery_state_1": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["low", "high"]
|
||||
}
|
||||
},
|
||||
"battery_state_2": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["low", "high"]
|
||||
}
|
||||
},
|
||||
"battery_state_3": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["low", "high"]
|
||||
}
|
||||
},
|
||||
"temp_current_external": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": -400,
|
||||
"max": 600,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"humidity_outdoor": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "%",
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"scale": 0,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"temp_current_external_1": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": -400,
|
||||
"max": 600,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"humidity_outdoor_1": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "%",
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"scale": 0,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"temp_current_external_2": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": -400,
|
||||
"max": 600,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"humidity_outdoor_2": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "%",
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"scale": 0,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"temp_current_external_3": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": -400,
|
||||
"max": 600,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"humidity_outdoor_3": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "%",
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"scale": 0,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"atmospheric_pressture": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "hPa",
|
||||
"min": 3000,
|
||||
"max": 12000,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"pressure_drop": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "hPa",
|
||||
"min": 0,
|
||||
"max": 15,
|
||||
"scale": 0,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"windspeed_avg": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "m/s",
|
||||
"min": 0,
|
||||
"max": 700,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"windspeed_gust": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "m/s",
|
||||
"min": 0,
|
||||
"max": 700,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"wind_direct": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": [
|
||||
"north",
|
||||
"north_north_east",
|
||||
"north_east",
|
||||
"east_north_east",
|
||||
"east",
|
||||
"east_south_east",
|
||||
"south_east",
|
||||
"south_south_east",
|
||||
"south",
|
||||
"south_south_west",
|
||||
"south_west",
|
||||
"west_south_west",
|
||||
"west",
|
||||
"west_north_west",
|
||||
"north_west",
|
||||
"north_north_west"
|
||||
]
|
||||
}
|
||||
},
|
||||
"rain_24h": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "mm",
|
||||
"min": 0,
|
||||
"max": 1000000,
|
||||
"scale": 3,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"rain_rate": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "mm",
|
||||
"min": 0,
|
||||
"max": 999999,
|
||||
"scale": 3,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"uv_index": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "",
|
||||
"min": 0,
|
||||
"max": 180,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"bright_value": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "lux",
|
||||
"min": 0,
|
||||
"max": 238000,
|
||||
"scale": 0,
|
||||
"step": 100
|
||||
}
|
||||
},
|
||||
"dew_point_temp": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": -400,
|
||||
"max": 800,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"feellike_temp": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": -650,
|
||||
"max": 500,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"heat_index": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": 260,
|
||||
"max": 500,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"windchill_index": {
|
||||
"type": "Integer",
|
||||
"value": {
|
||||
"unit": "\u2103",
|
||||
"min": -650,
|
||||
"max": 600,
|
||||
"scale": 1,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"com_index": {
|
||||
"type": "Enum",
|
||||
"value": {
|
||||
"range": ["moist", "dry", "comfortable"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"temp_current": 240,
|
||||
"humidity_value": 52,
|
||||
"battery_state": "high",
|
||||
"temp_unit_convert": "c",
|
||||
"windspeed_unit_convert": "m_s",
|
||||
"pressure_unit_convert": "hpa",
|
||||
"rain_unit_convert": "mm",
|
||||
"bright_unit_convert": "lux",
|
||||
"fault_type": "normal",
|
||||
"battery_status": "low",
|
||||
"battery_state_1": "high",
|
||||
"battery_state_2": "high",
|
||||
"battery_state_3": "low",
|
||||
"temp_current_external": -400,
|
||||
"humidity_outdoor": 0,
|
||||
"temp_current_external_1": 193,
|
||||
"humidity_outdoor_1": 99,
|
||||
"temp_current_external_2": 252,
|
||||
"humidity_outdoor_2": 0,
|
||||
"temp_current_external_3": -400,
|
||||
"humidity_outdoor_3": 0,
|
||||
"atmospheric_pressture": 10040,
|
||||
"pressure_drop": 0,
|
||||
"windspeed_avg": 0,
|
||||
"windspeed_gust": 0,
|
||||
"wind_direct": "none",
|
||||
"rain_24h": 0,
|
||||
"rain_rate": 0,
|
||||
"uv_index": 0,
|
||||
"bright_value": 0,
|
||||
"dew_point_temp": -400,
|
||||
"feellike_temp": -650,
|
||||
"heat_index": 260,
|
||||
"windchill_index": -650,
|
||||
"com_index": "none"
|
||||
},
|
||||
"set_up": false,
|
||||
"support_local": true
|
||||
}
|
@ -1265,6 +1265,485 @@
|
||||
'state': '100.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_temp_humidity_external_probe][sensor.frysen_battery_state-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.frysen_battery_state',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Battery state',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'battery_state',
|
||||
'unique_id': 'tuya.bff00f6abe0563b284t77pbattery_state',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_temp_humidity_external_probe][sensor.frysen_battery_state-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Frysen Battery state',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.frysen_battery_state',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'high',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_temp_humidity_external_probe][sensor.frysen_humidity-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.frysen_humidity',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.HUMIDITY: 'humidity'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Humidity',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'humidity',
|
||||
'unique_id': 'tuya.bff00f6abe0563b284t77phumidity_value',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_temp_humidity_external_probe][sensor.frysen_humidity-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'humidity',
|
||||
'friendly_name': 'Frysen Humidity',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.frysen_humidity',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '38.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_temp_humidity_external_probe][sensor.frysen_probe_temperature-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.frysen_probe_temperature',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
'suggested_display_precision': 1,
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Probe temperature',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'temperature_external',
|
||||
'unique_id': 'tuya.bff00f6abe0563b284t77ptemp_current_external',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_temp_humidity_external_probe][sensor.frysen_probe_temperature-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'Frysen Probe temperature',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.frysen_probe_temperature',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '-13.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_temp_humidity_external_probe][sensor.frysen_temperature-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.frysen_temperature',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
'suggested_display_precision': 1,
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Temperature',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'temperature',
|
||||
'unique_id': 'tuya.bff00f6abe0563b284t77ptemp_current',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_temp_humidity_external_probe][sensor.frysen_temperature-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'Frysen Temperature',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.frysen_temperature',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '22.2',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_weather_station][sensor.br_7_in_1_wlan_wetterstation_anthrazit_battery_state-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.br_7_in_1_wlan_wetterstation_anthrazit_battery_state',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Battery state',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'battery_state',
|
||||
'unique_id': 'tuya.bf84c743a84eb2c8abeurzbattery_state',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_weather_station][sensor.br_7_in_1_wlan_wetterstation_anthrazit_battery_state-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'BR 7-in-1 WLAN Wetterstation Anthrazit Battery state',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.br_7_in_1_wlan_wetterstation_anthrazit_battery_state',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'high',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_weather_station][sensor.br_7_in_1_wlan_wetterstation_anthrazit_humidity-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.br_7_in_1_wlan_wetterstation_anthrazit_humidity',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.HUMIDITY: 'humidity'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Humidity',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'humidity',
|
||||
'unique_id': 'tuya.bf84c743a84eb2c8abeurzhumidity_value',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_weather_station][sensor.br_7_in_1_wlan_wetterstation_anthrazit_humidity-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'humidity',
|
||||
'friendly_name': 'BR 7-in-1 WLAN Wetterstation Anthrazit Humidity',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.br_7_in_1_wlan_wetterstation_anthrazit_humidity',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '52.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_weather_station][sensor.br_7_in_1_wlan_wetterstation_anthrazit_illuminance-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.br_7_in_1_wlan_wetterstation_anthrazit_illuminance',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.ILLUMINANCE: 'illuminance'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Illuminance',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'illuminance',
|
||||
'unique_id': 'tuya.bf84c743a84eb2c8abeurzbright_value',
|
||||
'unit_of_measurement': 'lx',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_weather_station][sensor.br_7_in_1_wlan_wetterstation_anthrazit_illuminance-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'illuminance',
|
||||
'friendly_name': 'BR 7-in-1 WLAN Wetterstation Anthrazit Illuminance',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'lx',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.br_7_in_1_wlan_wetterstation_anthrazit_illuminance',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '0.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_weather_station][sensor.br_7_in_1_wlan_wetterstation_anthrazit_probe_temperature-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.br_7_in_1_wlan_wetterstation_anthrazit_probe_temperature',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
'suggested_display_precision': 1,
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Probe temperature',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'temperature_external',
|
||||
'unique_id': 'tuya.bf84c743a84eb2c8abeurztemp_current_external',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_weather_station][sensor.br_7_in_1_wlan_wetterstation_anthrazit_probe_temperature-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'BR 7-in-1 WLAN Wetterstation Anthrazit Probe temperature',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.br_7_in_1_wlan_wetterstation_anthrazit_probe_temperature',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '-40.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_weather_station][sensor.br_7_in_1_wlan_wetterstation_anthrazit_temperature-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.br_7_in_1_wlan_wetterstation_anthrazit_temperature',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
'suggested_display_precision': 1,
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Temperature',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'temperature',
|
||||
'unique_id': 'tuya.bf84c743a84eb2c8abeurztemp_current',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[qxj_weather_station][sensor.br_7_in_1_wlan_wetterstation_anthrazit_temperature-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'BR 7-in-1 WLAN Wetterstation Anthrazit Temperature',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.br_7_in_1_wlan_wetterstation_anthrazit_temperature',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '24.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[rqbj_gas_sensor][sensor.gas_sensor_gas-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
77
tests/components/yolink/conftest.py
Normal file
77
tests/components/yolink/conftest.py
Normal file
@ -0,0 +1,77 @@
|
||||
"""Provide common fixtures for the YoLink integration tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Generator
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from yolink.home_manager import YoLinkHome
|
||||
|
||||
from homeassistant.components.application_credentials import (
|
||||
ClientCredential,
|
||||
async_import_client_credential,
|
||||
)
|
||||
from homeassistant.components.yolink.api import ConfigEntryAuth
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
CLIENT_ID = "12345"
|
||||
CLIENT_SECRET = "6789"
|
||||
DOMAIN = "yolink"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def setup_credentials(hass: HomeAssistant) -> None:
|
||||
"""Fixture to setup credentials."""
|
||||
assert await async_setup_component(hass, "application_credentials", {})
|
||||
await async_import_client_credential(
|
||||
hass,
|
||||
DOMAIN,
|
||||
ClientCredential(CLIENT_ID, CLIENT_SECRET),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="mock_auth_manager")
|
||||
def mock_auth_manager() -> Generator[MagicMock]:
|
||||
"""Mock the authentication manager."""
|
||||
with patch(
|
||||
"homeassistant.components.yolink.api.ConfigEntryAuth", autospec=True
|
||||
) as mock_auth:
|
||||
mock_auth.return_value = MagicMock(spec=ConfigEntryAuth)
|
||||
yield mock_auth
|
||||
|
||||
|
||||
@pytest.fixture(name="mock_yolink_home")
|
||||
def mock_yolink_home() -> Generator[AsyncMock]:
|
||||
"""Mock YoLink home instance."""
|
||||
with patch(
|
||||
"homeassistant.components.yolink.YoLinkHome", autospec=True
|
||||
) as mock_home:
|
||||
mock_home.return_value = AsyncMock(spec=YoLinkHome)
|
||||
yield mock_home
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_config_entry(hass: HomeAssistant) -> MockConfigEntry:
|
||||
"""Mock a config entry for YoLink."""
|
||||
config_entry = MockConfigEntry(
|
||||
unique_id=DOMAIN,
|
||||
domain=DOMAIN,
|
||||
title="yolink",
|
||||
data={
|
||||
"auth_implementation": DOMAIN,
|
||||
"token": {
|
||||
"refresh_token": "mock-refresh-token",
|
||||
"access_token": "mock-access-token",
|
||||
"type": "Bearer",
|
||||
"expires_in": 60,
|
||||
"scope": "create",
|
||||
},
|
||||
},
|
||||
options={},
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
return config_entry
|
38
tests/components/yolink/test_init.py
Normal file
38
tests/components/yolink/test_init.py
Normal file
@ -0,0 +1,38 @@
|
||||
"""Tests for the yolink integration."""
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.yolink import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("setup_credentials", "mock_auth_manager", "mock_yolink_home")
|
||||
async def test_device_remove_devices(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test we can only remove a device that no longer exists."""
|
||||
|
||||
device_registry.async_get_or_create(
|
||||
config_entry_id=mock_config_entry.entry_id,
|
||||
identifiers={(DOMAIN, "stale_device_id")},
|
||||
)
|
||||
device_entries = dr.async_entries_for_config_entry(
|
||||
device_registry, mock_config_entry.entry_id
|
||||
)
|
||||
|
||||
assert len(device_entries) == 1
|
||||
device_entry = device_entries[0]
|
||||
assert device_entry.identifiers == {(DOMAIN, "stale_device_id")}
|
||||
|
||||
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
device_entries = dr.async_entries_for_config_entry(
|
||||
device_registry, mock_config_entry.entry_id
|
||||
)
|
||||
assert len(device_entries) == 0
|
Loading…
x
Reference in New Issue
Block a user