diff --git a/homeassistant/components/switchbot_cloud/__init__.py b/homeassistant/components/switchbot_cloud/__init__.py index 744d513f521..44206fe0ff3 100644 --- a/homeassistant/components/switchbot_cloud/__init__.py +++ b/homeassistant/components/switchbot_cloud/__init__.py @@ -1,4 +1,4 @@ -"""The SwitchBot via API integration.""" +"""SwitchBot via API integration.""" from asyncio import gather from dataclasses import dataclass, field @@ -15,7 +15,7 @@ from .const import DOMAIN from .coordinator import SwitchBotCoordinator _LOGGER = getLogger(__name__) -PLATFORMS: list[Platform] = [Platform.CLIMATE, Platform.SWITCH] +PLATFORMS: list[Platform] = [Platform.CLIMATE, Platform.SENSOR, Platform.SWITCH] @dataclass @@ -24,6 +24,7 @@ class SwitchbotDevices: climates: list[Remote] = field(default_factory=list) switches: list[Device | Remote] = field(default_factory=list) + sensors: list[Device] = field(default_factory=list) @dataclass @@ -72,6 +73,10 @@ def make_device_data( devices_data.switches.append( prepare_device(hass, api, device, coordinators_by_id) ) + if isinstance(device, Device) and device.device_type == "MeterPlus": + devices_data.sensors.append( + prepare_device(hass, api, device, coordinators_by_id) + ) return devices_data diff --git a/homeassistant/components/switchbot_cloud/const.py b/homeassistant/components/switchbot_cloud/const.py index b90a2f3a2ec..6c07d8f2b8b 100644 --- a/homeassistant/components/switchbot_cloud/const.py +++ b/homeassistant/components/switchbot_cloud/const.py @@ -5,4 +5,5 @@ from typing import Final DOMAIN: Final = "switchbot_cloud" ENTRY_TITLE = "SwitchBot Cloud" -SCAN_INTERVAL = timedelta(seconds=600) +DEFAULT_SCAN_INTERVAL = timedelta(seconds=600) +DEVICE_SCAN_INTERVAL = {"MeterPlus": timedelta(seconds=60)} diff --git a/homeassistant/components/switchbot_cloud/coordinator.py b/homeassistant/components/switchbot_cloud/coordinator.py index 4c12e03a6f2..37ce2302dfe 100644 --- a/homeassistant/components/switchbot_cloud/coordinator.py +++ b/homeassistant/components/switchbot_cloud/coordinator.py @@ -9,7 +9,7 @@ from switchbot_api import CannotConnect, Device, Remote, SwitchBotAPI from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from .const import DOMAIN, SCAN_INTERVAL +from .const import DEFAULT_SCAN_INTERVAL, DEVICE_SCAN_INTERVAL, DOMAIN _LOGGER = getLogger(__name__) @@ -21,7 +21,6 @@ class SwitchBotCoordinator(DataUpdateCoordinator[Status]): _api: SwitchBotAPI _device_id: str - _should_poll = False def __init__( self, hass: HomeAssistant, api: SwitchBotAPI, device: Device | Remote @@ -31,7 +30,8 @@ class SwitchBotCoordinator(DataUpdateCoordinator[Status]): hass, _LOGGER, name=DOMAIN, - update_interval=SCAN_INTERVAL, + update_interval=DEVICE_SCAN_INTERVAL[device.device_type] + or DEFAULT_SCAN_INTERVAL, ) self._api = api self._device_id = device.device_id diff --git a/homeassistant/components/switchbot_cloud/entity.py b/homeassistant/components/switchbot_cloud/entity.py index 7bb00cda945..a8baadd7b6f 100644 --- a/homeassistant/components/switchbot_cloud/entity.py +++ b/homeassistant/components/switchbot_cloud/entity.py @@ -23,11 +23,12 @@ class SwitchBotCloudEntity(CoordinatorEntity[SwitchBotCoordinator]): api: SwitchBotAPI, device: Device | Remote, coordinator: SwitchBotCoordinator, + id_suffix="", # Add suffix for multi-entity devices ) -> None: """Initialize the entity.""" super().__init__(coordinator) self._api = api - self._attr_unique_id = device.device_id + self._attr_unique_id = f"{device.device_id}{id_suffix}" self._attr_device_info = DeviceInfo( identifiers={(DOMAIN, device.device_id)}, name=device.device_name, diff --git a/homeassistant/components/switchbot_cloud/manifest.json b/homeassistant/components/switchbot_cloud/manifest.json index cb651e5c84f..271fc692b75 100644 --- a/homeassistant/components/switchbot_cloud/manifest.json +++ b/homeassistant/components/switchbot_cloud/manifest.json @@ -1,10 +1,11 @@ { "domain": "switchbot_cloud", "name": "SwitchBot Cloud", - "codeowners": ["@SeraphicRav"], + "codeowners": ["@SeraphicRav", "@PreslandBoy"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/switchbot_cloud", "iot_class": "cloud_polling", "loggers": ["switchbot-api"], - "requirements": ["switchbot-api==2.0.0"] + "requirements": ["switchbot-api==2.0.0"], + "integration_type": "hub" } diff --git a/homeassistant/components/switchbot_cloud/sensor.py b/homeassistant/components/switchbot_cloud/sensor.py new file mode 100644 index 00000000000..20be563ec79 --- /dev/null +++ b/homeassistant/components/switchbot_cloud/sensor.py @@ -0,0 +1,119 @@ +"""Platform for sensor integration.""" + +from __future__ import annotations + +from switchbot_api import Device, SwitchBotAPI + +from homeassistant.components.sensor import ( + SensorDeviceClass, + SensorEntity, + SensorStateClass, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import UnitOfTemperature +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from . import SwitchbotCloudData +from .const import DOMAIN +from .coordinator import SwitchBotCoordinator +from .entity import SwitchBotCloudEntity + + +async def async_setup_entry( + hass: HomeAssistant, + config: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up SwitchBot Cloud entry.""" + data: SwitchbotCloudData = hass.data[DOMAIN][config.entry_id] + + entities_to_add = [] + + for device, coordinator in data.devices.sensors: + entities_to_add.append( + _async_make_entity( + data.api, device, coordinator, SensorDeviceClass.TEMPERATURE + ) + ) + entities_to_add.append( + _async_make_entity( + data.api, device, coordinator, SensorDeviceClass.HUMIDITY + ) + ) + entities_to_add.append( + _async_make_entity(data.api, device, coordinator, SensorDeviceClass.BATTERY) + ) + + async_add_entities(entities_to_add) + + +class SwitchBotCloudHumiditySensor( + SwitchBotCloudEntity, CoordinatorEntity, SensorEntity +): + """Representation of a Humidity Sensor.""" + + _attr_name = "Humidity" + _attr_native_unit_of_measurement = "%" + _attr_device_class = SensorDeviceClass.HUMIDITY + _attr_state_class = SensorStateClass.MEASUREMENT + + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + if self.coordinator.data: + self._attr_native_value = self.coordinator.data.get("humidity") + self.async_write_ha_state() + + +class SwitchBotCloudTemperatureSensor( + SwitchBotCloudEntity, CoordinatorEntity, SensorEntity +): + """Representation of a Temperature Sensor.""" + + _attr_name = "Temperature" + _attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS + _attr_device_class = SensorDeviceClass.TEMPERATURE + _attr_state_class = SensorStateClass.MEASUREMENT + + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + if self.coordinator.data: + self._attr_native_value = self.coordinator.data.get("temperature") + self.async_write_ha_state() + + +class SwitchBotCloudBatterySensor( + SwitchBotCloudEntity, CoordinatorEntity, SensorEntity +): + """Representation of a Battery Sensor.""" + + _attr_name = "Battery" + _attr_native_unit_of_measurement = "%" + _attr_device_class = SensorDeviceClass.BATTERY + _attr_state_class = SensorStateClass.MEASUREMENT + + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + if self.coordinator.data: + self._attr_native_value = self.coordinator.data.get("battery") + self.async_write_ha_state() + + +@callback +def _async_make_entity( + api: SwitchBotAPI, + device: Device, + coordinator: SwitchBotCoordinator, + device_class: SensorDeviceClass, +) -> SensorEntity: + """Make a SwitchBotCloud Sensor.""" + if device_class == SensorDeviceClass.TEMPERATURE: + return SwitchBotCloudTemperatureSensor(api, device, coordinator, "temperature") + if device_class == SensorDeviceClass.HUMIDITY: + return SwitchBotCloudHumiditySensor(api, device, coordinator, "humidity") + if device_class == SensorDeviceClass.BATTERY: + return SwitchBotCloudBatterySensor(api, device, coordinator, "battery")