core/homeassistant/components/switchbot/sensor.py

134 lines
4.5 KiB
Python
Raw Normal View History

"""Support for SwitchBot sensors."""
from __future__ import annotations
from homeassistant.components.bluetooth import async_last_service_info
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
PERCENTAGE,
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
UnitOfPower,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
Update switchbot to be local push (#75645) * Update switchbot to be local push * fixes * fixes * fixes * fixes * adjust * cover is not assumed anymore * cleanups * adjust * adjust * add missing cover * import compat * fixes * uses lower * uses lower * bleak users upper case addresses * fixes * bump * keep conf_mac and deprecated options for rollback * reuse coordinator * adjust * move around * move around * move around * move around * refactor fixes * compat with DataUpdateCoordinator * fix available * Update homeassistant/components/bluetooth/passive_update_processor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/bluetooth/passive_update_coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/bluetooth/update_coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Split bluetooth coordinator into PassiveBluetoothDataUpdateCoordinator and PassiveBluetoothProcessorCoordinator The PassiveBluetoothDataUpdateCoordinator is now used to replace instances of DataUpdateCoordinator where the data is coming from bluetooth advertisements, and the integration may also mix in active updates The PassiveBluetoothProcessorCoordinator is used for integrations that want to process each bluetooth advertisement with multiple processors which can be dispatched to individual platforms or areas or the integration as it chooes * change connections * reduce code churn to reduce review overhead * reduce code churn to reduce review overhead * Update homeassistant/components/bluetooth/passive_update_coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * add basic test * add basic test * complete coverage * Update homeassistant/components/switchbot/coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/switchbot/coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/switchbot/__init__.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/switchbot/__init__.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * lint Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2022-07-24 16:38:45 +00:00
from .const import DOMAIN
from .coordinator import SwitchbotDataUpdateCoordinator
from .entity import SwitchbotEntity
PARALLEL_UPDATES = 0
SENSOR_TYPES: dict[str, SensorEntityDescription] = {
"rssi": SensorEntityDescription(
key="rssi",
name="Bluetooth signal strength",
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
entity_category=EntityCategory.DIAGNOSTIC,
),
"wifi_rssi": SensorEntityDescription(
key="wifi_rssi",
name="Wi-Fi signal strength",
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
entity_category=EntityCategory.DIAGNOSTIC,
),
"battery": SensorEntityDescription(
key="battery",
name="Battery",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.BATTERY,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
"lightLevel": SensorEntityDescription(
key="lightLevel",
name="Light level",
native_unit_of_measurement="Level",
state_class=SensorStateClass.MEASUREMENT,
),
"humidity": SensorEntityDescription(
key="humidity",
name="Humidity",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.HUMIDITY,
),
"temperature": SensorEntityDescription(
key="temperature",
name="Temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.TEMPERATURE,
),
"power": SensorEntityDescription(
key="power",
name="Power",
native_unit_of_measurement=UnitOfPower.WATT,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.POWER,
),
}
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Switchbot sensor based on a config entry."""
Update switchbot to be local push (#75645) * Update switchbot to be local push * fixes * fixes * fixes * fixes * adjust * cover is not assumed anymore * cleanups * adjust * adjust * add missing cover * import compat * fixes * uses lower * uses lower * bleak users upper case addresses * fixes * bump * keep conf_mac and deprecated options for rollback * reuse coordinator * adjust * move around * move around * move around * move around * refactor fixes * compat with DataUpdateCoordinator * fix available * Update homeassistant/components/bluetooth/passive_update_processor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/bluetooth/passive_update_coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/bluetooth/update_coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Split bluetooth coordinator into PassiveBluetoothDataUpdateCoordinator and PassiveBluetoothProcessorCoordinator The PassiveBluetoothDataUpdateCoordinator is now used to replace instances of DataUpdateCoordinator where the data is coming from bluetooth advertisements, and the integration may also mix in active updates The PassiveBluetoothProcessorCoordinator is used for integrations that want to process each bluetooth advertisement with multiple processors which can be dispatched to individual platforms or areas or the integration as it chooes * change connections * reduce code churn to reduce review overhead * reduce code churn to reduce review overhead * Update homeassistant/components/bluetooth/passive_update_coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * add basic test * add basic test * complete coverage * Update homeassistant/components/switchbot/coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/switchbot/coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/switchbot/__init__.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/switchbot/__init__.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * lint Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2022-07-24 16:38:45 +00:00
coordinator: SwitchbotDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
entities = [
SwitchBotSensor(coordinator, sensor)
for sensor in coordinator.device.parsed_data
if sensor in SENSOR_TYPES
]
entities.append(SwitchbotRSSISensor(coordinator, "rssi"))
async_add_entities(entities)
class SwitchBotSensor(SwitchbotEntity, SensorEntity):
"""Representation of a Switchbot sensor."""
def __init__(
self,
coordinator: SwitchbotDataUpdateCoordinator,
sensor: str,
) -> None:
"""Initialize the Switchbot sensor."""
super().__init__(coordinator)
self._sensor = sensor
self._attr_unique_id = f"{coordinator.base_unique_id}-{sensor}"
self.entity_description = SENSOR_TYPES[sensor]
@property
def native_value(self) -> str | int | None:
"""Return the state of the sensor."""
return self.parsed_data[self._sensor]
class SwitchbotRSSISensor(SwitchBotSensor):
"""Representation of a Switchbot RSSI sensor."""
@property
def native_value(self) -> str | int | None:
"""Return the state of the sensor."""
# Switchbot supports both connectable and non-connectable devices
# so we need to request the rssi value based on the connectable instead
# of the nearest scanner since that is the RSSI that matters for controlling
# the device.
if service_info := async_last_service_info(
self.hass, self._address, self.coordinator.connectable
):
return service_info.rssi
return None