Add support for Tasmota status sensor (#41782)
* Add sensor attributes, remove useless test. * Fix tests * Rework handling of sensor attributes * Remove unused sensor attributes * Hide status sensors * Bump hatasmota to 0.0.19 * Use DEVICE_CLASS_SIGNAL_STRENGTH for WiFi signal sensor * Improve test coverage * Fix tests
This commit is contained in:
parent
4da6c22338
commit
ec7f329807
8 changed files with 90 additions and 37 deletions
|
@ -25,6 +25,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||
SUPPORTED_PLATFORMS = [
|
||||
"binary_sensor",
|
||||
"light",
|
||||
"sensor",
|
||||
"switch",
|
||||
]
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Tasmota (beta)",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/tasmota",
|
||||
"requirements": ["hatasmota==0.0.18"],
|
||||
"requirements": ["hatasmota==0.0.19"],
|
||||
"dependencies": ["mqtt"],
|
||||
"mqtt": ["tasmota/discovery/#"],
|
||||
"codeowners": ["@emontnemery"]
|
||||
|
|
|
@ -33,6 +33,7 @@ from hatasmota.const import (
|
|||
SENSOR_PRESSUREATSEALEVEL,
|
||||
SENSOR_PROXIMITY,
|
||||
SENSOR_REACTIVE_POWERUSAGE,
|
||||
SENSOR_STATUS_SIGNAL,
|
||||
SENSOR_TEMPERATURE,
|
||||
SENSOR_TODAY,
|
||||
SENSOR_TOTAL,
|
||||
|
@ -50,8 +51,10 @@ from homeassistant.const import (
|
|||
DEVICE_CLASS_ILLUMINANCE,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
|
@ -95,6 +98,7 @@ SENSOR_DEVICE_CLASS_ICON_MAP = {
|
|||
SENSOR_PRESSUREATSEALEVEL: {DEVICE_CLASS: DEVICE_CLASS_PRESSURE},
|
||||
SENSOR_PROXIMITY: {ICON: "mdi:ruler"},
|
||||
SENSOR_REACTIVE_POWERUSAGE: {DEVICE_CLASS: DEVICE_CLASS_POWER},
|
||||
SENSOR_STATUS_SIGNAL: {DEVICE_CLASS: DEVICE_CLASS_SIGNAL_STRENGTH},
|
||||
SENSOR_TEMPERATURE: {DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE},
|
||||
SENSOR_TODAY: {DEVICE_CLASS: DEVICE_CLASS_POWER},
|
||||
SENSOR_TOTAL: {DEVICE_CLASS: DEVICE_CLASS_POWER},
|
||||
|
@ -131,13 +135,19 @@ class TasmotaSensor(TasmotaAvailability, TasmotaDiscoveryUpdate, Entity):
|
|||
|
||||
def __init__(self, **kwds):
|
||||
"""Initialize the Tasmota sensor."""
|
||||
self._state = False
|
||||
self._state = None
|
||||
|
||||
super().__init__(
|
||||
discovery_update=self.discovery_update,
|
||||
**kwds,
|
||||
)
|
||||
|
||||
@callback
|
||||
def state_updated(self, state, **kwargs):
|
||||
"""Handle state updates."""
|
||||
self._state = state
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
def device_class(self) -> Optional[str]:
|
||||
"""Return the device class of the sensor."""
|
||||
|
@ -146,6 +156,14 @@ class TasmotaSensor(TasmotaAvailability, TasmotaDiscoveryUpdate, Entity):
|
|||
)
|
||||
return class_or_icon.get(DEVICE_CLASS)
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||
# Hide status sensors to not overwhelm users
|
||||
if self._tasmota_entity.quantity == SENSOR_STATUS_SIGNAL:
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Return the icon."""
|
||||
|
|
|
@ -729,7 +729,7 @@ hass-nabucasa==0.37.1
|
|||
hass_splunk==0.1.1
|
||||
|
||||
# homeassistant.components.tasmota
|
||||
hatasmota==0.0.18
|
||||
hatasmota==0.0.19
|
||||
|
||||
# homeassistant.components.jewish_calendar
|
||||
hdate==0.9.5
|
||||
|
|
|
@ -364,7 +364,7 @@ hangups==0.4.11
|
|||
hass-nabucasa==0.37.1
|
||||
|
||||
# homeassistant.components.tasmota
|
||||
hatasmota==0.0.18
|
||||
hatasmota==0.0.19
|
||||
|
||||
# homeassistant.components.jewish_calendar
|
||||
hdate==0.9.5
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"""Test fixtures for Tasmota component."""
|
||||
|
||||
from hatasmota.discovery import get_status_sensor_entities
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries
|
||||
|
@ -43,6 +44,20 @@ def disable_debounce():
|
|||
yield
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def status_sensor_disabled():
|
||||
"""Fixture to allow overriding MQTT config."""
|
||||
return True
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def disable_status_sensor(status_sensor_disabled):
|
||||
"""Disable Tasmota status sensor."""
|
||||
wraps = None if status_sensor_disabled else get_status_sensor_entities
|
||||
with patch("hatasmota.discovery.get_status_sensor_entities", wraps=wraps):
|
||||
yield
|
||||
|
||||
|
||||
async def setup_tasmota_helper(hass):
|
||||
"""Set up Tasmota."""
|
||||
hass.config.components.add("tasmota")
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
import copy
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.tasmota.const import DEFAULT_PREFIX
|
||||
from homeassistant.components.tasmota.discovery import ALREADY_DISCOVERED
|
||||
|
||||
|
@ -174,37 +172,6 @@ async def test_device_update(
|
|||
assert device_entry.sw_version == "v6.6.6"
|
||||
|
||||
|
||||
@pytest.mark.no_fail_on_log_exception
|
||||
async def test_discovery_broken(hass, mqtt_mock, caplog, device_reg, setup_tasmota):
|
||||
"""Test handling of exception when creating discovered device."""
|
||||
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||
mac = config["mac"]
|
||||
data = json.dumps(config)
|
||||
|
||||
# Trigger an exception when the entity is added
|
||||
with patch(
|
||||
"hatasmota.discovery.get_device_config_helper",
|
||||
return_value=object(),
|
||||
):
|
||||
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", data)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Verify device entry is not created
|
||||
device_entry = device_reg.async_get_device(set(), {("mac", mac)})
|
||||
assert device_entry is None
|
||||
assert (
|
||||
"Exception in async_discover_device when dispatching 'tasmota_discovery_device'"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", data)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Verify device entry is created
|
||||
device_entry = device_reg.async_get_device(set(), {("mac", mac)})
|
||||
assert device_entry is not None
|
||||
|
||||
|
||||
async def test_device_remove(
|
||||
hass, mqtt_mock, caplog, device_reg, entity_reg, setup_tasmota
|
||||
):
|
||||
|
|
|
@ -7,6 +7,7 @@ from hatasmota.utils import (
|
|||
get_topic_tele_sensor,
|
||||
get_topic_tele_will,
|
||||
)
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import sensor
|
||||
from homeassistant.components.tasmota.const import DEFAULT_PREFIX
|
||||
|
@ -217,6 +218,57 @@ async def test_indexed_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
|
|||
assert state.state == "7.8"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("status_sensor_disabled", [False])
|
||||
async def test_status_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
|
||||
"""Test state update via MQTT."""
|
||||
entity_reg = await hass.helpers.entity_registry.async_get_registry()
|
||||
|
||||
# Pre-enable the status sensor
|
||||
entity_reg.async_get_or_create(
|
||||
sensor.DOMAIN,
|
||||
"tasmota",
|
||||
"00000049A3BC_status_sensor_status_sensor_status_signal",
|
||||
suggested_object_id="tasmota_status",
|
||||
disabled_by=None,
|
||||
)
|
||||
|
||||
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||
mac = config["mac"]
|
||||
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
f"{DEFAULT_PREFIX}/{mac}/config",
|
||||
json.dumps(config),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("sensor.tasmota_status")
|
||||
assert state.state == "unavailable"
|
||||
assert not state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online")
|
||||
state = hass.states.get("sensor.tasmota_status")
|
||||
assert state.state == STATE_UNKNOWN
|
||||
assert not state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
# Test pushed state update
|
||||
async_fire_mqtt_message(
|
||||
hass, "tasmota_49A3BC/tele/STATE", '{"Wifi":{"Signal":20.5}}'
|
||||
)
|
||||
state = hass.states.get("sensor.tasmota_status")
|
||||
assert state.state == "20.5"
|
||||
|
||||
# Test polled state update
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"tasmota_49A3BC/stat/STATUS11",
|
||||
'{"StatusSTS":{"Wifi":{"Signal":20.0}}}',
|
||||
)
|
||||
state = hass.states.get("sensor.tasmota_status")
|
||||
assert state.state == "20.0"
|
||||
|
||||
|
||||
async def test_attributes(hass, mqtt_mock, setup_tasmota):
|
||||
"""Test correct attributes for sensors."""
|
||||
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||
|
|
Loading…
Add table
Reference in a new issue