8000 Set state for MQTT entities to 'unavailable' when no connection to broker by definitio · Pull Request #36479 · home-assistant/core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Set state for MQTT entities to 'unavailable' when no connection to broker #36479

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion homeassistant/components/mqtt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from homeassistant.core import Event, ServiceCall, callback
from homeassistant.exceptions import HomeAssistantError, Unauthorized
from homeassistant.helpers import config_validation as cv, event, template
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.typing import ConfigType, HomeAssistantType, ServiceDataType
from homeassistant.loader import bind_hass
Expand All @@ -51,6 +51,8 @@
CONF_STATE_TOPIC,
DEFAULT_DISCOVERY,
DEFAULT_QOS,
MQTT_CONNECTED,
MQTT_DISCONNECTED,
PROTOCOL_311,
)
from .debug_info import log_messages
Expand Down Expand Up @@ -923,6 +925,7 @@ def _mqtt_on_connect(self, _mqttc, _userdata, _flags, result_code: int) -> None:
return

self.connected = True
dispatcher_send(self.hass, MQTT_CONNECTED)
_LOGGER.info("Connected to MQTT server (%s)", result_code)

# Group subscriptions to only re-subscribe once for each topic.
Expand Down Expand Up @@ -990,6 +993,7 @@ def _mqtt_handle_message(self, msg) -> None:
def _mqtt_on_disconnect(self, _mqttc, _userdata, result_code: int) -> None:
"""Disconnected callback."""
self.connected = False
dispatcher_send(self.hass, MQTT_DISCONNECTED)
_LOGGER.warning("Disconnected from MQTT server (%s)", result_code)


Expand Down Expand Up @@ -1099,6 +1103,8 @@ async def async_added_to_hass(self) -> None:
"""Subscribe MQTT events."""
await super().async_added_to_hass()
await self._availability_subscribe_topics()
async_dispatcher_connect(self.hass, MQTT_CONNECTED, self.async_mqtt_connect)
async_dispatcher_connect(self.hass, MQTT_DISCONNECTED, self.async_mqtt_connect)

async def availability_discovery_update(self, config: dict):
"""Handle updated discovery message."""
Expand Down Expand Up @@ -1131,6 +1137,11 @@ def availability_message_received(msg: Message) -> None:
},
)

@callback
def async_mqtt_connect(self):
"""Update state on connection/disconnection to MQTT broker."""
self.async_write_ha_state()

async def async_will_remove_from_hass(self):
"""Unsubscribe when removed."""
self._availability_sub_state = await async_unsubscribe_topics(
Expand All @@ -1141,6 +1152,8 @@ async def async_will_remove_from_hass(self):
def available(self) -> bool:
"""Return if the device is available."""
availability_topic = self._avail_config.get(CONF_AVAILABILITY_TOPIC)
if not self.hass.data[DATA_MQTT].connected:
return False
return availability_topic is None or self._available


Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/mqtt/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
CONF_STATE_TOPIC = "state_topic"
PROTOCOL_311 = "3.1.1"
DEFAULT_QOS = 0

MQTT_CONNECTED = "mqtt_connected"
MQTT_DISCONNECTED = "mqtt_disconnected"
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
)

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -469,6 +470,13 @@ async def test_attributes_code_text(hass, mqtt_mock):
)


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
8000 hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG_CODE
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import homeassistant.util.dt as dt_util

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -298,6 +299,13 @@ async def test_invalid_device_class(hass, mqtt_mock):
assert state is None


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from homeassistant.setup import async_setup_component

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -62,6 +63,13 @@ async def test_run_camera_setup(hass, aiohttp_client):
assert body == "beer"


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from homeassistant.const import STATE_OFF

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -608,6 +609,13 @@ async def test_set_aux(hass, mqtt_mock):
assert state.attributes.get("aux_heat") == "off"


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
18 changes: 18 additions & 0 deletions tests/components/mqtt/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

from homeassistant.components import mqtt
from homeassistant.components.mqtt import debug_info
from homeassistant.components.mqtt.const import MQTT_DISCONNECTED
from homeassistant.components.mqtt.discovery import async_start
from homeassistant.const import ATTR_ASSUMED_STATE, STATE_UNAVAILABLE
from homeassistant.helpers.dispatcher import async_dispatcher_send

from tests.async_mock import ANY
from tests.common import (
Expand Down Expand Up @@ -35,6 +37,22 @@
}


async def help_test_availability_when_connection_lost(hass, mqtt_mock, domain, config):
"""Test availability after MQTT disconnection."""
assert await async_setup_component(hass, domain, config)
await hass.async_block_till_done()

state = hass.states.get(f"{domain}.test")
assert state.state != STATE_UNAVAILABLE

mqtt_mock.connected = False
async_dispatcher_send(hass, MQTT_DISCONNECTED)
await hass.async_block_till_done()

state = hass.states.get(f"{domain}.test")
assert state.state == STATE_UNAVAILABLE


async def help_test_availability_without_topic(hass, mqtt_mock, domain, config):
"""Test availability without defined availability topic."""
assert "availability_topic" not in config[domain]
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from homeassistant.setup import async_setup_component

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -1735,6 +1736,13 @@ async def test_find_in_range_altered_inverted(hass, mqtt_mock):
assert mqtt_cover.find_in_range_from_percent(60, "cover") == 120


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, cover.DOMAIN, DEFAULT_CONFIG
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from homeassistant.setup import async_setup_component

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -600,6 +601,13 @@ async def test_supported_features(hass, mqtt_mock):
)


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_legacy_vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from homeassistant.setup import async_setup_component

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -543,6 +544,13 @@ async def test_missing_fan_speed_template(hass, mqtt_mock):
assert state is None


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_light.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
from homeassistant.setup import async_setup_component

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -1326,6 +1327,13 @@ async def test_effect(hass, mqtt_mock):
mqtt_mock.async_publish.assert_called_once_with("test_light/set", "OFF", 0, False)


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT d 3D11 isconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_light_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
from homeassistant.setup import async_setup_component

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -1065,6 +1066,13 @@ async def test_invalid_values(hass, mqtt_mock):
assert state.attributes.get("color_temp") == 100


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_light_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from homeassistant.setup import async_setup_component

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -797,6 +798,13 @@ async def test_invalid_values(hass, mqtt_mock):
assert state.attributes.get("effect") == "rainbow"


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from homeassistant.setup import async_setup_component

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -272,6 +273,13 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock):
assert state.attributes.get(ATTR_ASSUMED_STATE)


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import homeassistant.util.dt as dt_util

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -232,6 +233,13 @@ def callback(event):
assert len(events) == 2


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
8 changes: 8 additions & 0 deletions tests/components/mqtt/test_state_vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from homeassistant.setup import async_setup_component

from .test_common import (
help_test_availability_when_connection_lost,
help_test_availability_without_topic,
help_test_custom_availability_payload,
help_test_default_availability_payload,
Expand Down Expand Up @@ -321,6 +322,13 @@ async def test_status_invalid_json(hass, mqtt_mock):
assert state.state == STATE_UNKNOWN


async def test_availability_when_connection_lost(hass, mqtt_mock):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
)


async def test_availability_without_topic(hass, mqtt_mock):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
Expand Down
Loading
0