From de35d58fd4f59cabb42baa3a0407ef225db8444c Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 23 Oct 2020 01:22:51 +0200 Subject: [PATCH] Support reloading Tasmota config entries (#42097) --- homeassistant/components/tasmota/__init__.py | 51 +++++++++++++-- .../components/tasmota/binary_sensor.py | 6 +- homeassistant/components/tasmota/const.py | 9 +++ .../components/tasmota/device_automation.py | 5 +- homeassistant/components/tasmota/discovery.py | 64 ++++++------------- homeassistant/components/tasmota/light.py | 6 +- .../components/tasmota/manifest.json | 2 +- homeassistant/components/tasmota/mixins.py | 6 ++ homeassistant/components/tasmota/sensor.py | 6 +- homeassistant/components/tasmota/switch.py | 6 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/tasmota/conftest.py | 1 + tests/components/tasmota/test_discovery.py | 25 ++++---- tests/components/tasmota/test_sensor.py | 63 +++++++++++++++++- 15 files changed, 179 insertions(+), 75 deletions(-) diff --git a/homeassistant/components/tasmota/__init__.py b/homeassistant/components/tasmota/__init__.py index 1e11aff448e..5754b98b71e 100644 --- a/homeassistant/components/tasmota/__init__.py +++ b/homeassistant/components/tasmota/__init__.py @@ -1,4 +1,5 @@ """The Tasmota integration.""" +import asyncio import logging from hatasmota.const import ( @@ -21,8 +22,8 @@ from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.typing import HomeAssistantType -from . import discovery -from .const import CONF_DISCOVERY_PREFIX +from . import device_automation, discovery +from .const import CONF_DISCOVERY_PREFIX, DATA_REMOVE_DISCOVER_COMPONENT, PLATFORMS from .discovery import TASMOTA_DISCOVERY_DEVICE _LOGGER = logging.getLogger(__name__) @@ -54,14 +55,52 @@ async def async_setup_entry(hass, entry): tasmota_mqtt = TasmotaMQTTClient(_publish, _subscribe_topics, _unsubscribe_topics) - discovery_prefix = entry.data[CONF_DISCOVERY_PREFIX] - await discovery.async_start(hass, discovery_prefix, entry, tasmota_mqtt) - async def async_discover_device(config, mac): """Discover and add a Tasmota device.""" await async_setup_device(hass, mac, config, entry, tasmota_mqtt) - async_dispatcher_connect(hass, TASMOTA_DISCOVERY_DEVICE, async_discover_device) + hass.data[ + DATA_REMOVE_DISCOVER_COMPONENT.format("device") + ] = async_dispatcher_connect(hass, TASMOTA_DISCOVERY_DEVICE, async_discover_device) + + async def start_platforms(): + await device_automation.async_setup_entry(hass, entry) + await asyncio.gather( + *[ + hass.config_entries.async_forward_entry_setup(entry, component) + for component in PLATFORMS + ] + ) + + discovery_prefix = entry.data[CONF_DISCOVERY_PREFIX] + await discovery.async_start(hass, discovery_prefix, entry, tasmota_mqtt) + + hass.async_create_task(start_platforms()) + return True + + +async def async_unload_entry(hass, entry): + """Unload a config entry.""" + + # cleanup platforms + unload_ok = all( + await asyncio.gather( + *[ + hass.config_entries.async_forward_entry_unload(entry, component) + for component in PLATFORMS + ] + ) + ) + if not unload_ok: + return False + + # disable discovery + await discovery.async_stop(hass) + hass.data.pop(DEVICE_MACS) + hass.data[DATA_REMOVE_DISCOVER_COMPONENT.format("device")]() + hass.data.pop(DATA_REMOVE_DISCOVER_COMPONENT.format("device_automation"))() + for component in PLATFORMS: + hass.data.pop(DATA_REMOVE_DISCOVER_COMPONENT.format(component))() return True diff --git a/homeassistant/components/tasmota/binary_sensor.py b/homeassistant/components/tasmota/binary_sensor.py index 549452c1949..ade309840ca 100644 --- a/homeassistant/components/tasmota/binary_sensor.py +++ b/homeassistant/components/tasmota/binary_sensor.py @@ -6,7 +6,7 @@ from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect import homeassistant.helpers.event as evt -from .const import DOMAIN as TASMOTA_DOMAIN +from .const import DATA_REMOVE_DISCOVER_COMPONENT, DOMAIN as TASMOTA_DOMAIN from .discovery import TASMOTA_DISCOVERY_ENTITY_NEW from .mixins import TasmotaAvailability, TasmotaDiscoveryUpdate @@ -25,7 +25,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): ] ) - async_dispatcher_connect( + hass.data[ + DATA_REMOVE_DISCOVER_COMPONENT.format(binary_sensor.DOMAIN) + ] = async_dispatcher_connect( hass, TASMOTA_DISCOVERY_ENTITY_NEW.format(binary_sensor.DOMAIN, TASMOTA_DOMAIN), async_discover, diff --git a/homeassistant/components/tasmota/const.py b/homeassistant/components/tasmota/const.py index 11f43ed38bf..7cddeb7a603 100644 --- a/homeassistant/components/tasmota/const.py +++ b/homeassistant/components/tasmota/const.py @@ -1,8 +1,17 @@ """Constants used by multiple Tasmota modules.""" CONF_DISCOVERY_PREFIX = "discovery_prefix" +DATA_REMOVE_DISCOVER_COMPONENT = "tasmota_discover_{}" + DEFAULT_PREFIX = "tasmota/discovery" DOMAIN = "tasmota" +PLATFORMS = [ + "binary_sensor", + "light", + "sensor", + "switch", +] + TASMOTA_EVENT = "tasmota_event" diff --git a/homeassistant/components/tasmota/device_automation.py b/homeassistant/components/tasmota/device_automation.py index 6bbd8ce6d89..e921a186fea 100644 --- a/homeassistant/components/tasmota/device_automation.py +++ b/homeassistant/components/tasmota/device_automation.py @@ -6,6 +6,7 @@ from homeassistant.helpers.device_registry import EVENT_DEVICE_REGISTRY_UPDATED from homeassistant.helpers.dispatcher import async_dispatcher_connect from . import device_trigger +from .const import DATA_REMOVE_DISCOVER_COMPONENT from .discovery import TASMOTA_DISCOVERY_ENTITY_NEW @@ -25,7 +26,9 @@ async def async_setup_entry(hass, config_entry): hass, tasmota_automation, config_entry, discovery_hash ) - async_dispatcher_connect( + hass.data[ + DATA_REMOVE_DISCOVER_COMPONENT.format("device_automation") + ] = async_dispatcher_connect( hass, TASMOTA_DISCOVERY_ENTITY_NEW.format("device_automation", "tasmota"), async_discover, diff --git a/homeassistant/components/tasmota/discovery.py b/homeassistant/components/tasmota/discovery.py index e137692445e..6d224a98707 100644 --- a/homeassistant/components/tasmota/discovery.py +++ b/homeassistant/components/tasmota/discovery.py @@ -1,5 +1,4 @@ """Support for Tasmota device discovery.""" -import asyncio import logging from hatasmota.discovery import ( @@ -9,7 +8,6 @@ from hatasmota.discovery import ( get_entity as tasmota_get_entity, get_trigger as tasmota_get_trigger, get_triggers as tasmota_get_triggers, - has_entities_with_platform as tasmota_has_entities_with_platform, unique_id_from_hash, ) @@ -18,23 +16,15 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.entity_registry import async_entries_for_device from homeassistant.helpers.typing import HomeAssistantType -from .const import DOMAIN +from .const import DOMAIN, PLATFORMS _LOGGER = logging.getLogger(__name__) -SUPPORTED_PLATFORMS = [ - "binary_sensor", - "light", - "sensor", - "switch", -] - ALREADY_DISCOVERED = "tasmota_discovered_components" -CONFIG_ENTRY_IS_SETUP = "tasmota_config_entry_is_setup" -DATA_CONFIG_ENTRY_LOCK = "tasmota_config_entry_lock" TASMOTA_DISCOVERY_DEVICE = "tasmota_discovery_device" TASMOTA_DISCOVERY_ENTITY_NEW = "tasmota_discovery_entity_new_{}" TASMOTA_DISCOVERY_ENTITY_UPDATED = "tasmota_discovery_entity_updated_{}_{}_{}_{}" +TASMOTA_DISCOVERY_INSTANCE = "tasmota_discovery_instance" def clear_discovery_hash(hass, discovery_hash): @@ -52,16 +42,6 @@ async def async_start( ) -> bool: """Start Tasmota device discovery.""" - async def _load_platform(platform): - """Load a Tasmota platform if not already done.""" - async with hass.data[DATA_CONFIG_ENTRY_LOCK]: - config_entries_key = f"{platform}.tasmota" - if config_entries_key not in hass.data[CONFIG_ENTRY_IS_SETUP]: - await hass.config_entries.async_forward_entry_setup( - config_entry, platform - ) - hass.data[CONFIG_ENTRY_IS_SETUP].add(config_entries_key) - async def _discover_entity(tasmota_entity_config, discovery_hash, platform): """Handle adding or updating a discovered entity.""" if not tasmota_entity_config: @@ -86,8 +66,13 @@ async def async_start( tasmota_entity_config, ) else: - _LOGGER.debug("Adding new entity: %s %s", platform, discovery_hash) tasmota_entity = tasmota_get_entity(tasmota_entity_config, tasmota_mqtt) + _LOGGER.debug( + "Adding new entity: %s %s %s", + platform, + discovery_hash, + tasmota_entity.unique_id, + ) hass.data[ALREADY_DISCOVERED][discovery_hash] = None @@ -102,7 +87,8 @@ async def async_start( """Process the received message.""" if ALREADY_DISCOVERED not in hass.data: - hass.data[ALREADY_DISCOVERED] = {} + # Discovery is shutting down + return _LOGGER.debug("Received discovery data for tasmota device: %s", mac) tasmota_device_config = tasmota_get_device_config(payload) @@ -114,17 +100,6 @@ async def async_start( return tasmota_triggers = tasmota_get_triggers(payload) - async with hass.data[DATA_CONFIG_ENTRY_LOCK]: - if any(trigger.is_active for trigger in tasmota_triggers): - config_entries_key = "device_automation.tasmota" - if config_entries_key not in hass.data[CONFIG_ENTRY_IS_SETUP]: - # Local import to avoid circular dependencies - # pylint: disable=import-outside-toplevel - from . import device_automation - - await device_automation.async_setup_entry(hass, config_entry) - hass.data[CONFIG_ENTRY_IS_SETUP].add(config_entries_key) - for trigger_config in tasmota_triggers: discovery_hash = (mac, "automation", "trigger", trigger_config.trigger_id) if discovery_hash in hass.data[ALREADY_DISCOVERED]: @@ -150,12 +125,7 @@ async def async_start( discovery_hash, ) - for platform in SUPPORTED_PLATFORMS: - if not tasmota_has_entities_with_platform(payload, platform): - continue - await _load_platform(platform) - - for platform in SUPPORTED_PLATFORMS: + for platform in PLATFORMS: tasmota_entities = tasmota_get_entities_for_platform(payload, platform) for (tasmota_entity_config, discovery_hash) in tasmota_entities: await _discover_entity(tasmota_entity_config, discovery_hash, platform) @@ -163,7 +133,6 @@ async def async_start( async def async_sensors_discovered(sensors, mac): """Handle discovery of (additional) sensors.""" platform = sensor.DOMAIN - await _load_platform(platform) device_registry = await hass.helpers.device_registry.async_get_registry() entity_registry = await hass.helpers.entity_registry.async_get_registry() @@ -188,10 +157,17 @@ async def async_start( _LOGGER.debug("Removing entity: %s %s", platform, entity_id) entity_registry.async_remove(entity_id) - hass.data[DATA_CONFIG_ENTRY_LOCK] = asyncio.Lock() - hass.data[CONFIG_ENTRY_IS_SETUP] = set() + hass.data[ALREADY_DISCOVERED] = {} tasmota_discovery = TasmotaDiscovery(discovery_topic, tasmota_mqtt) await tasmota_discovery.start_discovery( async_device_discovered, async_sensors_discovered ) + hass.data[TASMOTA_DISCOVERY_INSTANCE] = tasmota_discovery + + +async def async_stop(hass: HomeAssistantType) -> bool: + """Stop Tasmota device discovery.""" + hass.data.pop(ALREADY_DISCOVERED) + tasmota_discovery = hass.data.pop(TASMOTA_DISCOVERY_INSTANCE) + await tasmota_discovery.stop_discovery() diff --git a/homeassistant/components/tasmota/light.py b/homeassistant/components/tasmota/light.py index 00cedc4a611..c761d3436df 100644 --- a/homeassistant/components/tasmota/light.py +++ b/homeassistant/components/tasmota/light.py @@ -27,7 +27,7 @@ from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect import homeassistant.util.color as color_util -from .const import DOMAIN as TASMOTA_DOMAIN +from .const import DATA_REMOVE_DISCOVER_COMPONENT, DOMAIN as TASMOTA_DOMAIN from .discovery import TASMOTA_DISCOVERY_ENTITY_NEW from .mixins import TasmotaAvailability, TasmotaDiscoveryUpdate @@ -45,7 +45,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): [TasmotaLight(tasmota_entity=tasmota_entity, discovery_hash=discovery_hash)] ) - async_dispatcher_connect( + hass.data[ + DATA_REMOVE_DISCOVER_COMPONENT.format(light.DOMAIN) + ] = async_dispatcher_connect( hass, TASMOTA_DISCOVERY_ENTITY_NEW.format(light.DOMAIN, TASMOTA_DOMAIN), async_discover, diff --git a/homeassistant/components/tasmota/manifest.json b/homeassistant/components/tasmota/manifest.json index 4157c416eca..b64d10c1070 100644 --- a/homeassistant/components/tasmota/manifest.json +++ b/homeassistant/components/tasmota/manifest.json @@ -3,7 +3,7 @@ "name": "Tasmota (beta)", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/tasmota", - "requirements": ["hatasmota==0.0.19"], + "requirements": ["hatasmota==0.0.20"], "dependencies": ["mqtt"], "mqtt": ["tasmota/discovery/#"], "codeowners": ["@emontnemery"] diff --git a/homeassistant/components/tasmota/mixins.py b/homeassistant/components/tasmota/mixins.py index 13e511e4a8f..3b52fafd12b 100644 --- a/homeassistant/components/tasmota/mixins.py +++ b/homeassistant/components/tasmota/mixins.py @@ -153,6 +153,12 @@ class TasmotaDiscoveryUpdate(TasmotaEntity): ) ) + @callback + def add_to_platform_abort(self) -> None: + """Abort adding an entity to a platform.""" + clear_discovery_hash(self.hass, self._discovery_hash) + super().add_to_platform_abort() + async def async_will_remove_from_hass(self) -> None: """Stop listening to signal and cleanup discovery data..""" if not self._removed_from_hass: diff --git a/homeassistant/components/tasmota/sensor.py b/homeassistant/components/tasmota/sensor.py index 660c0efc1e6..076ca457a23 100644 --- a/homeassistant/components/tasmota/sensor.py +++ b/homeassistant/components/tasmota/sensor.py @@ -58,7 +58,7 @@ from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity import Entity -from .const import DOMAIN as TASMOTA_DOMAIN +from .const import DATA_REMOVE_DISCOVER_COMPONENT, DOMAIN as TASMOTA_DOMAIN from .discovery import TASMOTA_DISCOVERY_ENTITY_NEW from .mixins import TasmotaAvailability, TasmotaDiscoveryUpdate @@ -123,7 +123,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): ] ) - async_dispatcher_connect( + hass.data[ + DATA_REMOVE_DISCOVER_COMPONENT.format(sensor.DOMAIN) + ] = async_dispatcher_connect( hass, TASMOTA_DISCOVERY_ENTITY_NEW.format(sensor.DOMAIN, TASMOTA_DOMAIN), async_discover_sensor, diff --git a/homeassistant/components/tasmota/switch.py b/homeassistant/components/tasmota/switch.py index fe8f4b9555c..0a97a5e2528 100644 --- a/homeassistant/components/tasmota/switch.py +++ b/homeassistant/components/tasmota/switch.py @@ -5,7 +5,7 @@ from homeassistant.components.switch import SwitchEntity from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import DOMAIN as TASMOTA_DOMAIN +from .const import DATA_REMOVE_DISCOVER_COMPONENT, DOMAIN as TASMOTA_DOMAIN from .discovery import TASMOTA_DISCOVERY_ENTITY_NEW from .mixins import TasmotaAvailability, TasmotaDiscoveryUpdate @@ -24,7 +24,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): ] ) - async_dispatcher_connect( + hass.data[ + DATA_REMOVE_DISCOVER_COMPONENT.format(switch.DOMAIN) + ] = async_dispatcher_connect( hass, TASMOTA_DISCOVERY_ENTITY_NEW.format(switch.DOMAIN, TASMOTA_DOMAIN), async_discover, diff --git a/requirements_all.txt b/requirements_all.txt index a16395394e0..86f22f13a0b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -732,7 +732,7 @@ hass-nabucasa==0.37.1 hass_splunk==0.1.1 # homeassistant.components.tasmota -hatasmota==0.0.19 +hatasmota==0.0.20 # homeassistant.components.jewish_calendar hdate==0.9.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 33b88cddc65..2bcbfb1a0c0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -367,7 +367,7 @@ hangups==0.4.11 hass-nabucasa==0.37.1 # homeassistant.components.tasmota -hatasmota==0.0.19 +hatasmota==0.0.20 # homeassistant.components.jewish_calendar hdate==0.9.5 diff --git a/tests/components/tasmota/conftest.py b/tests/components/tasmota/conftest.py index 456d157547d..09a3bfa4d63 100644 --- a/tests/components/tasmota/conftest.py +++ b/tests/components/tasmota/conftest.py @@ -72,6 +72,7 @@ async def setup_tasmota_helper(hass): entry.add_to_hass(hass) assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() assert "tasmota" in hass.config.components diff --git a/tests/components/tasmota/test_discovery.py b/tests/components/tasmota/test_discovery.py index f337b062839..607676615a7 100644 --- a/tests/components/tasmota/test_discovery.py +++ b/tests/components/tasmota/test_discovery.py @@ -27,40 +27,41 @@ async def test_valid_discovery_message(hass, mqtt_mock, caplog): config = copy.deepcopy(DEFAULT_CONFIG) with patch( - "homeassistant.components.tasmota.discovery.tasmota_has_entities_with_platform" - ) as mock_tasmota_has_entities: + "homeassistant.components.tasmota.discovery.tasmota_get_device_config", + return_value={}, + ) as mock_tasmota_get_device_config: await setup_tasmota_helper(hass) async_fire_mqtt_message( hass, f"{DEFAULT_PREFIX}/00000049A3BC/config", json.dumps(config) ) await hass.async_block_till_done() - assert mock_tasmota_has_entities.called + assert mock_tasmota_get_device_config.called async def test_invalid_topic(hass, mqtt_mock): """Test receiving discovery message on wrong topic.""" with patch( - "homeassistant.components.tasmota.discovery.tasmota_has_entities_with_platform" - ) as mock_tasmota_has_entities: + "homeassistant.components.tasmota.discovery.tasmota_get_device_config" + ) as mock_tasmota_get_device_config: await setup_tasmota_helper(hass) async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/123456/configuration", "{}") await hass.async_block_till_done() - assert not mock_tasmota_has_entities.called + assert not mock_tasmota_get_device_config.called async def test_invalid_message(hass, mqtt_mock, caplog): """Test receiving an invalid message.""" with patch( - "homeassistant.components.tasmota.discovery.tasmota_has_entities_with_platform" - ) as mock_tasmota_has_entities: + "homeassistant.components.tasmota.discovery.tasmota_get_device_config" + ) as mock_tasmota_get_device_config: await setup_tasmota_helper(hass) async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/123456/config", "asd") await hass.async_block_till_done() assert "Invalid discovery message" in caplog.text - assert not mock_tasmota_has_entities.called + assert not mock_tasmota_get_device_config.called async def test_invalid_mac(hass, mqtt_mock, caplog): @@ -68,8 +69,8 @@ async def test_invalid_mac(hass, mqtt_mock, caplog): config = copy.deepcopy(DEFAULT_CONFIG) with patch( - "homeassistant.components.tasmota.discovery.tasmota_has_entities_with_platform" - ) as mock_tasmota_has_entities: + "homeassistant.components.tasmota.discovery.tasmota_get_device_config" + ) as mock_tasmota_get_device_config: await setup_tasmota_helper(hass) async_fire_mqtt_message( @@ -77,7 +78,7 @@ async def test_invalid_mac(hass, mqtt_mock, caplog): ) await hass.async_block_till_done() assert "MAC mismatch" in caplog.text - assert not mock_tasmota_has_entities.called + assert not mock_tasmota_get_device_config.called async def test_correct_config_discovery( diff --git a/tests/components/tasmota/test_sensor.py b/tests/components/tasmota/test_sensor.py index 859c0f735ee..ab8498ed04c 100644 --- a/tests/components/tasmota/test_sensor.py +++ b/tests/components/tasmota/test_sensor.py @@ -1,5 +1,6 @@ """The tests for the Tasmota sensor platform.""" import copy +from datetime import timedelta import json from hatasmota.utils import ( @@ -9,9 +10,11 @@ from hatasmota.utils import ( ) import pytest +from homeassistant import config_entries from homeassistant.components import sensor from homeassistant.components.tasmota.const import DEFAULT_PREFIX from homeassistant.const import ATTR_ASSUMED_STATE, STATE_UNKNOWN +from homeassistant.util import dt from .test_common import ( DEFAULT_CONFIG, @@ -27,7 +30,7 @@ from .test_common import ( ) from tests.async_mock import patch -from tests.common import async_fire_mqtt_message +from tests.common import async_fire_mqtt_message, async_fire_time_changed DEFAULT_SENSOR_CONFIG = { "sn": { @@ -377,6 +380,64 @@ async def test_indexed_sensor_attributes(hass, mqtt_mock, setup_tasmota): assert state.attributes.get("unit_of_measurement") == "ppm" +@pytest.mark.parametrize("status_sensor_disabled", [False]) +async def test_enable_status_sensor(hass, mqtt_mock, setup_tasmota): + """Test enabling status sensor.""" + entity_reg = await hass.helpers.entity_registry.async_get_registry() + + 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 is None + entry = entity_reg.async_get("sensor.tasmota_status") + assert entry.disabled + assert entry.disabled_by == "integration" + + # Enable the status sensor + updated_entry = entity_reg.async_update_entity( + "sensor.tasmota_status", disabled_by=None + ) + assert updated_entry != entry + assert updated_entry.disabled is False + await hass.async_block_till_done() + + async_fire_time_changed( + hass, + dt.utcnow() + + timedelta( + seconds=config_entries.EntityRegistryDisabledHandler.RELOAD_AFTER_UPDATE_DELAY + + 1 + ), + ) + await hass.async_block_till_done() + + # Fake re-send of retained discovery message + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/config", + json.dumps(config), + ) + 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) + + async def test_availability_when_connection_lost( hass, mqtt_client_mock, mqtt_mock, setup_tasmota ):