Entities for secondary temperature values created by certain Xiaomi devices in deCONZ (#49724)
* Create sensors for secondary temperature values created by certain Xiaomi devices * Fix testspull/49742/head
parent
b27e9e376d
commit
58ad3b61f7
|
@ -114,6 +114,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
):
|
||||
entities.append(DeconzSensor(sensor, gateway))
|
||||
|
||||
if sensor.secondary_temperature:
|
||||
known_temperature_sensors = set(gateway.entities[DOMAIN])
|
||||
new_temperature_sensor = DeconzTemperature(sensor, gateway)
|
||||
if new_temperature_sensor.unique_id not in known_temperature_sensors:
|
||||
entities.append(new_temperature_sensor)
|
||||
|
||||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
|
@ -192,6 +198,47 @@ class DeconzSensor(DeconzDevice, SensorEntity):
|
|||
return attr
|
||||
|
||||
|
||||
class DeconzTemperature(DeconzDevice, SensorEntity):
|
||||
"""Representation of a deCONZ temperature sensor.
|
||||
|
||||
Extra temperature sensor on certain Xiaomi devices.
|
||||
"""
|
||||
|
||||
TYPE = DOMAIN
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return a unique identifier for this device."""
|
||||
return f"{self.serial}-temperature"
|
||||
|
||||
@callback
|
||||
def async_update_callback(self, force_update=False):
|
||||
"""Update the sensor's state."""
|
||||
keys = {"temperature", "reachable"}
|
||||
if force_update or self._device.changed_keys.intersection(keys):
|
||||
super().async_update_callback(force_update=force_update)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the sensor."""
|
||||
return self._device.secondary_temperature
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the temperature sensor."""
|
||||
return f"{self._device.name} Temperature"
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return the class of the sensor."""
|
||||
return DEVICE_CLASS_TEMPERATURE
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement of this sensor."""
|
||||
return TEMP_CELSIUS
|
||||
|
||||
|
||||
class DeconzBattery(DeconzDevice, SensorEntity):
|
||||
"""Battery class for when a device is only represented as an event."""
|
||||
|
||||
|
|
|
@ -13,7 +13,13 @@ from homeassistant.components.deconz.const import (
|
|||
DOMAIN as DECONZ_DOMAIN,
|
||||
)
|
||||
from homeassistant.components.deconz.services import SERVICE_DEVICE_REFRESH
|
||||
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE
|
||||
from homeassistant.const import (
|
||||
ATTR_DEVICE_CLASS,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_registry import async_entries_for_config_entry
|
||||
|
||||
|
@ -72,15 +78,21 @@ async def test_binary_sensors(hass, aioclient_mock, mock_deconz_websocket):
|
|||
with patch.dict(DECONZ_WEB_REQUEST, data):
|
||||
config_entry = await setup_deconz_integration(hass, aioclient_mock)
|
||||
|
||||
assert len(hass.states.async_all()) == 3
|
||||
assert len(hass.states.async_all()) == 5
|
||||
presence_sensor = hass.states.get("binary_sensor.presence_sensor")
|
||||
assert presence_sensor.state == STATE_OFF
|
||||
assert presence_sensor.attributes["device_class"] == DEVICE_CLASS_MOTION
|
||||
assert presence_sensor.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_MOTION
|
||||
presence_temp = hass.states.get("sensor.presence_sensor_temperature")
|
||||
assert presence_temp.state == "0.1"
|
||||
assert presence_temp.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_TEMPERATURE
|
||||
assert hass.states.get("binary_sensor.temperature_sensor") is None
|
||||
assert hass.states.get("binary_sensor.clip_presence_sensor") is None
|
||||
vibration_sensor = hass.states.get("binary_sensor.vibration_sensor")
|
||||
assert vibration_sensor.state == STATE_ON
|
||||
assert vibration_sensor.attributes["device_class"] == DEVICE_CLASS_VIBRATION
|
||||
assert vibration_sensor.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_VIBRATION
|
||||
vibration_temp = hass.states.get("sensor.vibration_sensor_temperature")
|
||||
assert vibration_temp.state == "0.1"
|
||||
assert vibration_temp.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_TEMPERATURE
|
||||
|
||||
event_changed_sensor = {
|
||||
"t": "event",
|
||||
|
|
|
@ -12,6 +12,7 @@ from homeassistant.const import (
|
|||
DEVICE_CLASS_BATTERY,
|
||||
DEVICE_CLASS_ILLUMINANCE,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
)
|
||||
|
@ -89,13 +90,17 @@ async def test_sensors(hass, aioclient_mock, mock_deconz_websocket):
|
|||
with patch.dict(DECONZ_WEB_REQUEST, data):
|
||||
config_entry = await setup_deconz_integration(hass, aioclient_mock)
|
||||
|
||||
assert len(hass.states.async_all()) == 5
|
||||
assert len(hass.states.async_all()) == 6
|
||||
|
||||
light_level_sensor = hass.states.get("sensor.light_level_sensor")
|
||||
assert light_level_sensor.state == "999.8"
|
||||
assert light_level_sensor.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_ILLUMINANCE
|
||||
assert light_level_sensor.attributes[ATTR_DAYLIGHT] == 6955
|
||||
|
||||
light_level_temp = hass.states.get("sensor.light_level_sensor_temperature")
|
||||
assert light_level_temp.state == "0.1"
|
||||
assert light_level_temp.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_TEMPERATURE
|
||||
|
||||
assert not hass.states.get("sensor.presence_sensor")
|
||||
assert not hass.states.get("sensor.switch_1")
|
||||
assert not hass.states.get("sensor.switch_1_battery_level")
|
||||
|
@ -130,6 +135,19 @@ async def test_sensors(hass, aioclient_mock, mock_deconz_websocket):
|
|||
|
||||
assert hass.states.get("sensor.light_level_sensor").state == "1.6"
|
||||
|
||||
# Event signals new temperature value
|
||||
|
||||
event_changed_sensor = {
|
||||
"t": "event",
|
||||
"e": "changed",
|
||||
"r": "sensors",
|
||||
"id": "1",
|
||||
"config": {"temperature": 100},
|
||||
}
|
||||
await mock_deconz_websocket(data=event_changed_sensor)
|
||||
|
||||
assert hass.states.get("sensor.light_level_sensor_temperature").state == "1.0"
|
||||
|
||||
# Event signals new battery level
|
||||
|
||||
event_changed_sensor = {
|
||||
|
@ -148,7 +166,7 @@ async def test_sensors(hass, aioclient_mock, mock_deconz_websocket):
|
|||
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
|
||||
states = hass.states.async_all()
|
||||
assert len(states) == 5
|
||||
assert len(states) == 6
|
||||
for state in states:
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
|
@ -187,7 +205,7 @@ async def test_allow_clip_sensors(hass, aioclient_mock):
|
|||
options={CONF_ALLOW_CLIP_SENSOR: True},
|
||||
)
|
||||
|
||||
assert len(hass.states.async_all()) == 2
|
||||
assert len(hass.states.async_all()) == 3
|
||||
assert hass.states.get("sensor.clip_light_level_sensor").state == "999.8"
|
||||
|
||||
# Disallow clip sensors
|
||||
|
@ -197,7 +215,7 @@ async def test_allow_clip_sensors(hass, aioclient_mock):
|
|||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 1
|
||||
assert len(hass.states.async_all()) == 2
|
||||
assert not hass.states.get("sensor.clip_light_level_sensor")
|
||||
|
||||
# Allow clip sensors
|
||||
|
@ -207,7 +225,7 @@ async def test_allow_clip_sensors(hass, aioclient_mock):
|
|||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 2
|
||||
assert len(hass.states.async_all()) == 3
|
||||
assert hass.states.get("sensor.clip_light_level_sensor").state == "999.8"
|
||||
|
||||
|
||||
|
@ -235,7 +253,7 @@ async def test_add_new_sensor(hass, aioclient_mock, mock_deconz_websocket):
|
|||
await mock_deconz_websocket(data=event_added_sensor)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 1
|
||||
assert len(hass.states.async_all()) == 2
|
||||
assert hass.states.get("sensor.light_level_sensor").state == "999.8"
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue