mirror of
https://github.com/home-assistant/core.git
synced 2025-11-12 12:30:31 +00:00
Compare commits
3 Commits
claude/tri
...
mqtt-clien
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1edea46a4d | ||
|
|
c476e92bdc | ||
|
|
8dcd9945e8 |
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/econet",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["paho_mqtt", "pyeconet"],
|
||||
"requirements": ["pyeconet==0.1.28"]
|
||||
"requirements": ["pyeconet==0.1.23"]
|
||||
}
|
||||
|
||||
@@ -6,14 +6,7 @@ from functools import lru_cache
|
||||
from types import TracebackType
|
||||
from typing import Self
|
||||
|
||||
from paho.mqtt.client import (
|
||||
CallbackOnConnect_v2,
|
||||
CallbackOnDisconnect_v2,
|
||||
CallbackOnPublish_v2,
|
||||
CallbackOnSubscribe_v2,
|
||||
CallbackOnUnsubscribe_v2,
|
||||
Client as MQTTClient,
|
||||
)
|
||||
from paho.mqtt.client import Client as MQTTClient
|
||||
|
||||
_MQTT_LOCK_COUNT = 7
|
||||
|
||||
@@ -51,12 +44,6 @@ class AsyncMQTTClient(MQTTClient):
|
||||
that is not needed since we are running in an async event loop.
|
||||
"""
|
||||
|
||||
on_connect: CallbackOnConnect_v2
|
||||
on_disconnect: CallbackOnDisconnect_v2
|
||||
on_publish: CallbackOnPublish_v2
|
||||
on_subscribe: CallbackOnSubscribe_v2
|
||||
on_unsubscribe: CallbackOnUnsubscribe_v2
|
||||
|
||||
def setup(self) -> None:
|
||||
"""Set up the client.
|
||||
|
||||
@@ -64,10 +51,10 @@ class AsyncMQTTClient(MQTTClient):
|
||||
since the client is running in an async event loop
|
||||
and will never run in multiple threads.
|
||||
"""
|
||||
self._in_callback_mutex = NullLock() # type: ignore[assignment]
|
||||
self._callback_mutex = NullLock() # type: ignore[assignment]
|
||||
self._msgtime_mutex = NullLock() # type: ignore[assignment]
|
||||
self._out_message_mutex = NullLock() # type: ignore[assignment]
|
||||
self._in_message_mutex = NullLock() # type: ignore[assignment]
|
||||
self._reconnect_delay_mutex = NullLock() # type: ignore[assignment]
|
||||
self._mid_generate_mutex = NullLock() # type: ignore[assignment]
|
||||
self._in_callback_mutex = NullLock()
|
||||
self._callback_mutex = NullLock()
|
||||
self._msgtime_mutex = NullLock()
|
||||
self._out_message_mutex = NullLock()
|
||||
self._in_message_mutex = NullLock()
|
||||
self._reconnect_delay_mutex = NullLock()
|
||||
self._mid_generate_mutex = NullLock()
|
||||
|
||||
@@ -15,6 +15,7 @@ import socket
|
||||
import ssl
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Any
|
||||
import uuid
|
||||
|
||||
import certifi
|
||||
|
||||
@@ -116,7 +117,7 @@ MAX_UNSUBSCRIBES_PER_CALL = 500
|
||||
|
||||
MAX_PACKETS_TO_READ = 500
|
||||
|
||||
type SocketType = socket.socket | ssl.SSLSocket | mqtt._WebsocketWrapper | Any # noqa: SLF001
|
||||
type SocketType = socket.socket | ssl.SSLSocket | mqtt.WebsocketWrapper | Any
|
||||
|
||||
type SubscribePayloadType = str | bytes | bytearray # Only bytes if encoding is None
|
||||
|
||||
@@ -298,39 +299,22 @@ class MqttClientSetup:
|
||||
from .async_client import AsyncMQTTClient
|
||||
|
||||
config = self._config
|
||||
clean_session: bool | None = None
|
||||
if (protocol := config.get(CONF_PROTOCOL, DEFAULT_PROTOCOL)) == PROTOCOL_31:
|
||||
proto = mqtt.MQTTv31
|
||||
clean_session = True
|
||||
elif protocol == PROTOCOL_5:
|
||||
proto = mqtt.MQTTv5
|
||||
else:
|
||||
proto = mqtt.MQTTv311
|
||||
clean_session = True
|
||||
|
||||
if (client_id := config.get(CONF_CLIENT_ID)) is None:
|
||||
# PAHO MQTT relies on the MQTT server to generate random client IDs.
|
||||
# However, that feature is not mandatory so we generate our own.
|
||||
client_id = None
|
||||
client_id = mqtt.base62(uuid.uuid4().int, padding=22)
|
||||
transport: str = config.get(CONF_TRANSPORT, DEFAULT_TRANSPORT)
|
||||
self._client = AsyncMQTTClient(
|
||||
callback_api_version=mqtt.CallbackAPIVersion.VERSION2,
|
||||
client_id=client_id,
|
||||
# See: https://eclipse.dev/paho/files/paho.mqtt.python/html/client.html
|
||||
# clean_session (bool defaults to None)
|
||||
# a boolean that determines the client type.
|
||||
# If True, the broker will remove all information about this client when it
|
||||
# disconnects. If False, the client is a persistent client and subscription
|
||||
# information and queued messages will be retained when the client
|
||||
# disconnects. Note that a client will never discard its own outgoing
|
||||
# messages on disconnect. Calling connect() or reconnect() will cause the
|
||||
# messages to be resent. Use reinitialise() to reset a client to its
|
||||
# original state. The clean_session argument only applies to MQTT versions
|
||||
# v3.1.1 and v3.1. It is not accepted if the MQTT version is v5.0 - use the
|
||||
# clean_start argument on connect() instead.
|
||||
clean_session=clean_session,
|
||||
client_id,
|
||||
protocol=proto,
|
||||
transport=transport, # type: ignore[arg-type]
|
||||
transport=transport,
|
||||
reconnect_on_failure=False,
|
||||
)
|
||||
self._client.setup()
|
||||
@@ -387,7 +371,6 @@ class MQTT:
|
||||
self.loop = hass.loop
|
||||
self.config_entry = config_entry
|
||||
self.conf = conf
|
||||
self.is_mqttv5 = conf.get(CONF_PROTOCOL, DEFAULT_PROTOCOL) == PROTOCOL_5
|
||||
|
||||
self._simple_subscriptions: defaultdict[str, set[Subscription]] = defaultdict(
|
||||
set
|
||||
@@ -493,9 +476,9 @@ class MQTT:
|
||||
mqttc.on_connect = self._async_mqtt_on_connect
|
||||
mqttc.on_disconnect = self._async_mqtt_on_disconnect
|
||||
mqttc.on_message = self._async_mqtt_on_message
|
||||
mqttc.on_publish = self._async_mqtt_on_publish
|
||||
mqttc.on_subscribe = self._async_mqtt_on_subscribe_unsubscribe
|
||||
mqttc.on_unsubscribe = self._async_mqtt_on_subscribe_unsubscribe
|
||||
mqttc.on_publish = self._async_mqtt_on_callback
|
||||
mqttc.on_subscribe = self._async_mqtt_on_callback
|
||||
mqttc.on_unsubscribe = self._async_mqtt_on_callback
|
||||
|
||||
# suppress exceptions at callback
|
||||
mqttc.suppress_exceptions = True
|
||||
@@ -515,7 +498,7 @@ class MQTT:
|
||||
def _async_reader_callback(self, client: mqtt.Client) -> None:
|
||||
"""Handle reading data from the socket."""
|
||||
if (status := client.loop_read(MAX_PACKETS_TO_READ)) != 0:
|
||||
self._async_handle_callback_exception(status)
|
||||
self._async_on_disconnect(status)
|
||||
|
||||
@callback
|
||||
def _async_start_misc_periodic(self) -> None:
|
||||
@@ -550,7 +533,7 @@ class MQTT:
|
||||
try:
|
||||
# Some operating systems do not allow us to set the preferred
|
||||
# buffer size. In that case we try some other size options.
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, new_buffer_size) # type: ignore[union-attr]
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, new_buffer_size)
|
||||
except OSError as err:
|
||||
if new_buffer_size <= MIN_BUFFER_SIZE:
|
||||
_LOGGER.warning(
|
||||
@@ -610,7 +593,7 @@ class MQTT:
|
||||
def _async_writer_callback(self, client: mqtt.Client) -> None:
|
||||
"""Handle writing data to the socket."""
|
||||
if (status := client.loop_write()) != 0:
|
||||
self._async_handle_callback_exception(status)
|
||||
self._async_on_disconnect(status)
|
||||
|
||||
def _on_socket_register_write(
|
||||
self, client: mqtt.Client, userdata: Any, sock: SocketType
|
||||
@@ -669,25 +652,14 @@ class MQTT:
|
||||
result: int | None = None
|
||||
self._available_future = client_available
|
||||
self._should_reconnect = True
|
||||
connect_partial = partial(
|
||||
self._mqttc.connect,
|
||||
host=self.conf[CONF_BROKER],
|
||||
port=self.conf.get(CONF_PORT, DEFAULT_PORT),
|
||||
keepalive=self.conf.get(CONF_KEEPALIVE, DEFAULT_KEEPALIVE),
|
||||
# See:
|
||||
# https://eclipse.dev/paho/files/paho.mqtt.python/html/client.html
|
||||
# `clean_start` (bool) – (MQTT v5.0 only) `True`, `False` or
|
||||
# `MQTT_CLEAN_START_FIRST_ONLY`. Sets the MQTT v5.0 clean_start flag
|
||||
# always, never or on the first successful connect only,
|
||||
# respectively. MQTT session data (such as outstanding messages and
|
||||
# subscriptions) is cleared on successful connect when the
|
||||
# clean_start flag is set. For MQTT v3.1.1, the clean_session
|
||||
# argument of Client should be used for similar result.
|
||||
clean_start=True if self.is_mqttv5 else mqtt.MQTT_CLEAN_START_FIRST_ONLY,
|
||||
)
|
||||
try:
|
||||
async with self._connection_lock, self._async_connect_in_executor():
|
||||
result = await self.hass.async_add_executor_job(connect_partial)
|
||||
result = await self.hass.async_add_executor_job(
|
||||
self._mqttc.connect,
|
||||
self.conf[CONF_BROKER],
|
||||
self.conf.get(CONF_PORT, DEFAULT_PORT),
|
||||
self.conf.get(CONF_KEEPALIVE, DEFAULT_KEEPALIVE),
|
||||
)
|
||||
except (OSError, mqtt.WebsocketConnectionError) as err:
|
||||
_LOGGER.error("Failed to connect to MQTT server due to exception: %s", err)
|
||||
self._async_connection_result(False)
|
||||
@@ -1011,9 +983,9 @@ class MQTT:
|
||||
self,
|
||||
_mqttc: mqtt.Client,
|
||||
_userdata: None,
|
||||
_connect_flags: mqtt.ConnectFlags,
|
||||
reason_code: mqtt.ReasonCode,
|
||||
_properties: mqtt.Properties | None = None,
|
||||
_flags: dict[str, int],
|
||||
result_code: int,
|
||||
properties: mqtt.Properties | None = None,
|
||||
) -> None:
|
||||
"""On connect callback.
|
||||
|
||||
@@ -1021,20 +993,19 @@ class MQTT:
|
||||
message.
|
||||
"""
|
||||
# pylint: disable-next=import-outside-toplevel
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
if reason_code.is_failure:
|
||||
# 24: Continue authentication
|
||||
# 25: Re-authenticate
|
||||
# 134: Bad user name or password
|
||||
# 135: Not authorized
|
||||
# 140: Bad authentication method
|
||||
if reason_code.value in (24, 25, 134, 135, 140):
|
||||
if result_code != mqtt.CONNACK_ACCEPTED:
|
||||
if result_code in (
|
||||
mqtt.CONNACK_REFUSED_BAD_USERNAME_PASSWORD,
|
||||
mqtt.CONNACK_REFUSED_NOT_AUTHORIZED,
|
||||
):
|
||||
self._should_reconnect = False
|
||||
self.hass.async_create_task(self.async_disconnect())
|
||||
self.config_entry.async_start_reauth(self.hass)
|
||||
_LOGGER.error(
|
||||
"Unable to connect to the MQTT broker: %s",
|
||||
reason_code.getName(), # type: ignore[no-untyped-call]
|
||||
mqtt.connack_string(result_code),
|
||||
)
|
||||
self._async_connection_result(False)
|
||||
return
|
||||
@@ -1045,7 +1016,7 @@ class MQTT:
|
||||
"Connected to MQTT server %s:%s (%s)",
|
||||
self.conf[CONF_BROKER],
|
||||
self.conf.get(CONF_PORT, DEFAULT_PORT),
|
||||
reason_code,
|
||||
result_code,
|
||||
)
|
||||
|
||||
birth: dict[str, Any]
|
||||
@@ -1182,32 +1153,18 @@ class MQTT:
|
||||
self._mqtt_data.state_write_requests.process_write_state_requests(msg)
|
||||
|
||||
@callback
|
||||
def _async_mqtt_on_publish(
|
||||
def _async_mqtt_on_callback(
|
||||
self,
|
||||
_mqttc: mqtt.Client,
|
||||
_userdata: None,
|
||||
mid: int,
|
||||
_reason_code: mqtt.ReasonCode,
|
||||
_properties: mqtt.Properties | None,
|
||||
_granted_qos_reason: tuple[int, ...] | mqtt.ReasonCodes | None = None,
|
||||
_properties_reason: mqtt.ReasonCodes | None = None,
|
||||
) -> None:
|
||||
"""Publish callback."""
|
||||
self._async_mqtt_on_callback(mid)
|
||||
|
||||
@callback
|
||||
def _async_mqtt_on_subscribe_unsubscribe(
|
||||
self,
|
||||
_mqttc: mqtt.Client,
|
||||
_userdata: None,
|
||||
mid: int,
|
||||
_reason_code: list[mqtt.ReasonCode],
|
||||
_properties: mqtt.Properties | None,
|
||||
) -> None:
|
||||
"""Subscribe / Unsubscribe callback."""
|
||||
self._async_mqtt_on_callback(mid)
|
||||
|
||||
@callback
|
||||
def _async_mqtt_on_callback(self, mid: int) -> None:
|
||||
"""Publish / Subscribe / Unsubscribe callback."""
|
||||
# The callback signature for on_unsubscribe is different from on_subscribe
|
||||
# see https://github.com/eclipse/paho.mqtt.python/issues/687
|
||||
# properties and reason codes are not used in Home Assistant
|
||||
future = self._async_get_mid_future(mid)
|
||||
if future.done() and (future.cancelled() or future.exception()):
|
||||
# Timed out or cancelled
|
||||
@@ -1223,28 +1180,19 @@ class MQTT:
|
||||
self._pending_operations[mid] = future
|
||||
return future
|
||||
|
||||
@callback
|
||||
def _async_handle_callback_exception(self, status: mqtt.MQTTErrorCode) -> None:
|
||||
"""Handle a callback exception."""
|
||||
# We don't import on the top because some integrations
|
||||
# should be able to optionally rely on MQTT.
|
||||
import paho.mqtt.client as mqtt # pylint: disable=import-outside-toplevel
|
||||
|
||||
_LOGGER.warning(
|
||||
"Error returned from MQTT server: %s",
|
||||
mqtt.error_string(status),
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_mqtt_on_disconnect(
|
||||
self,
|
||||
_mqttc: mqtt.Client,
|
||||
_userdata: None,
|
||||
_disconnect_flags: mqtt.DisconnectFlags,
|
||||
reason_code: mqtt.ReasonCode,
|
||||
result_code: int,
|
||||
properties: mqtt.Properties | None = None,
|
||||
) -> None:
|
||||
"""Disconnected callback."""
|
||||
self._async_on_disconnect(result_code)
|
||||
|
||||
@callback
|
||||
def _async_on_disconnect(self, result_code: int) -> None:
|
||||
if not self.connected:
|
||||
# This function is re-entrant and may be called multiple times
|
||||
# when there is a broken pipe error.
|
||||
@@ -1255,11 +1203,11 @@ class MQTT:
|
||||
self.connected = False
|
||||
async_dispatcher_send(self.hass, MQTT_CONNECTION_STATE, False)
|
||||
_LOGGER.log(
|
||||
logging.INFO if reason_code == 0 else logging.DEBUG,
|
||||
logging.INFO if result_code == 0 else logging.DEBUG,
|
||||
"Disconnected from MQTT server %s:%s (%s)",
|
||||
self.conf[CONF_BROKER],
|
||||
self.conf.get(CONF_PORT, DEFAULT_PORT),
|
||||
reason_code,
|
||||
result_code,
|
||||
)
|
||||
|
||||
@callback
|
||||
@@ -1268,9 +1216,7 @@ class MQTT:
|
||||
if not future.done():
|
||||
future.set_exception(asyncio.TimeoutError)
|
||||
|
||||
async def _async_wait_for_mid_or_raise(
|
||||
self, mid: int | None, result_code: int
|
||||
) -> None:
|
||||
async def _async_wait_for_mid_or_raise(self, mid: int, result_code: int) -> None:
|
||||
"""Wait for ACK from broker or raise on error."""
|
||||
if result_code != 0:
|
||||
# pylint: disable-next=import-outside-toplevel
|
||||
@@ -1286,8 +1232,6 @@ class MQTT:
|
||||
|
||||
# Create the mid event if not created, either _mqtt_handle_mid or
|
||||
# _async_wait_for_mid_or_raise may be executed first.
|
||||
if TYPE_CHECKING:
|
||||
assert mid is not None
|
||||
future = self._async_get_mid_future(mid)
|
||||
loop = self.hass.loop
|
||||
timer_handle = loop.call_later(TIMEOUT_ACK, self._async_timeout_mid, future)
|
||||
@@ -1325,7 +1269,7 @@ def _matcher_for_topic(subscription: str) -> Callable[[str], bool]:
|
||||
# pylint: disable-next=import-outside-toplevel
|
||||
from paho.mqtt.matcher import MQTTMatcher
|
||||
|
||||
matcher = MQTTMatcher() # type: ignore[no-untyped-call]
|
||||
matcher = MQTTMatcher()
|
||||
matcher[subscription] = True
|
||||
|
||||
return lambda topic: next(matcher.iter_match(topic), False) # type: ignore[no-untyped-call]
|
||||
return lambda topic: next(matcher.iter_match(topic), False)
|
||||
|
||||
@@ -1023,14 +1023,14 @@ def try_connection(
|
||||
result: queue.Queue[bool] = queue.Queue(maxsize=1)
|
||||
|
||||
def on_connect(
|
||||
_mqttc: mqtt.Client,
|
||||
_userdata: None,
|
||||
_connect_flags: mqtt.ConnectFlags,
|
||||
reason_code: mqtt.ReasonCode,
|
||||
_properties: mqtt.Properties | None = None,
|
||||
client_: mqtt.Client,
|
||||
userdata: None,
|
||||
flags: dict[str, Any],
|
||||
result_code: int,
|
||||
properties: mqtt.Properties | None = None,
|
||||
) -> None:
|
||||
"""Handle connection result."""
|
||||
result.put(not reason_code.is_failure)
|
||||
result.put(result_code == mqtt.CONNACK_ACCEPTED)
|
||||
|
||||
client.on_connect = on_connect
|
||||
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/mqtt",
|
||||
"iot_class": "local_push",
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["paho-mqtt==2.1.0"],
|
||||
"requirements": ["paho-mqtt==1.6.1"],
|
||||
"single_config_entry": true
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ lru-dict==1.3.0
|
||||
mutagen==1.47.0
|
||||
orjson==3.10.12
|
||||
packaging>=23.1
|
||||
paho-mqtt==2.1.0
|
||||
paho-mqtt==1.6.1
|
||||
Pillow==11.1.0
|
||||
propcache==0.3.0
|
||||
psutil-home-assistant==0.0.1
|
||||
|
||||
4
requirements_all.txt
generated
4
requirements_all.txt
generated
@@ -1622,7 +1622,7 @@ ovoenergy==2.0.0
|
||||
p1monitor==3.1.0
|
||||
|
||||
# homeassistant.components.mqtt
|
||||
paho-mqtt==2.1.0
|
||||
paho-mqtt==1.6.1
|
||||
|
||||
# homeassistant.components.panasonic_bluray
|
||||
panacotta==0.2
|
||||
@@ -1918,7 +1918,7 @@ pyebox==1.1.4
|
||||
pyecoforest==0.4.0
|
||||
|
||||
# homeassistant.components.econet
|
||||
pyeconet==0.1.28
|
||||
pyeconet==0.1.23
|
||||
|
||||
# homeassistant.components.ista_ecotrend
|
||||
pyecotrend-ista==3.3.1
|
||||
|
||||
@@ -41,6 +41,7 @@ types-beautifulsoup4==4.12.0.20250204
|
||||
types-caldav==1.3.0.20241107
|
||||
types-chardet==0.1.5
|
||||
types-decorator==5.1.8.20250121
|
||||
types-paho-mqtt==1.6.0.20240321
|
||||
types-pexpect==4.9.0.20241208
|
||||
types-pillow==10.2.0.20240822
|
||||
types-protobuf==5.29.1.20241207
|
||||
|
||||
4
requirements_test_all.txt
generated
4
requirements_test_all.txt
generated
@@ -1352,7 +1352,7 @@ ovoenergy==2.0.0
|
||||
p1monitor==3.1.0
|
||||
|
||||
# homeassistant.components.mqtt
|
||||
paho-mqtt==2.1.0
|
||||
paho-mqtt==1.6.1
|
||||
|
||||
# homeassistant.components.panasonic_viera
|
||||
panasonic-viera==0.4.2
|
||||
@@ -1565,7 +1565,7 @@ pydroid-ipcam==2.0.0
|
||||
pyecoforest==0.4.0
|
||||
|
||||
# homeassistant.components.econet
|
||||
pyeconet==0.1.28
|
||||
pyeconet==0.1.23
|
||||
|
||||
# homeassistant.components.ista_ecotrend
|
||||
pyecotrend-ista==3.3.1
|
||||
|
||||
@@ -199,6 +199,7 @@ EXCEPTIONS = {
|
||||
"pigpio", # https://github.com/joan2937/pigpio/pull/608
|
||||
"pymitv", # MIT
|
||||
"pybbox", # https://github.com/HydrelioxGitHub/pybbox/pull/5
|
||||
"pyeconet", # https://github.com/w1ll1am23/pyeconet/pull/41
|
||||
"pysabnzbd", # https://github.com/jeradM/pysabnzbd/pull/6
|
||||
"pyvera", # https://github.com/maximvelichko/pyvera/pull/164
|
||||
"repoze.lru",
|
||||
|
||||
@@ -410,25 +410,6 @@ def async_mock_intent(hass: HomeAssistant, intent_typ: str) -> list[intent.Inten
|
||||
return intents
|
||||
|
||||
|
||||
class MockMqttReasonCode:
|
||||
"""Class to fake a MQTT ReasonCode."""
|
||||
|
||||
value: int
|
||||
is_failure: bool
|
||||
|
||||
def __init__(
|
||||
self, value: int = 0, is_failure: bool = False, name: str = "Success"
|
||||
) -> None:
|
||||
"""Initialize the mock reason code."""
|
||||
self.value = value
|
||||
self.is_failure = is_failure
|
||||
self._name = name
|
||||
|
||||
def getName(self) -> str:
|
||||
"""Return the name of the reason code."""
|
||||
return self._name
|
||||
|
||||
|
||||
@callback
|
||||
def async_fire_mqtt_message(
|
||||
hass: HomeAssistant,
|
||||
|
||||
@@ -32,7 +32,6 @@ from .test_common import help_all_subscribe_calls
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
MockMqttReasonCode,
|
||||
async_fire_mqtt_message,
|
||||
async_fire_time_changed,
|
||||
)
|
||||
@@ -95,7 +94,7 @@ async def test_mqtt_await_ack_at_disconnect(hass: HomeAssistant) -> None:
|
||||
mqtt_client.connect = MagicMock(
|
||||
return_value=0,
|
||||
side_effect=lambda *args, **kwargs: hass.loop.call_soon_threadsafe(
|
||||
mqtt_client.on_connect, mqtt_client, None, 0, MockMqttReasonCode()
|
||||
mqtt_client.on_connect, mqtt_client, None, 0, 0, 0
|
||||
),
|
||||
)
|
||||
mqtt_client.publish = MagicMock(return_value=FakeInfo())
|
||||
@@ -120,7 +119,7 @@ async def test_mqtt_await_ack_at_disconnect(hass: HomeAssistant) -> None:
|
||||
)
|
||||
await asyncio.sleep(0)
|
||||
# Simulate late ACK callback from client with mid 100
|
||||
mqtt_client.on_publish(0, 0, 100, MockMqttReasonCode(), None)
|
||||
mqtt_client.on_publish(0, 0, 100)
|
||||
# disconnect the MQTT client
|
||||
await hass.async_stop()
|
||||
await hass.async_block_till_done()
|
||||
@@ -779,10 +778,10 @@ async def test_replaying_payload_same_topic(
|
||||
calls_a = []
|
||||
calls_b = []
|
||||
mqtt_client_mock.reset_mock()
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
|
||||
mock_debouncer.clear()
|
||||
mqtt_client_mock.on_connect(None, None, None, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(None, None, None, 0)
|
||||
await mock_debouncer.wait()
|
||||
mqtt_client_mock.subscribe.assert_called()
|
||||
# Simulate a (retained) message played back after reconnecting
|
||||
@@ -909,10 +908,10 @@ async def test_replaying_payload_wildcard_topic(
|
||||
calls_a = []
|
||||
calls_b = []
|
||||
mqtt_client_mock.reset_mock()
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
|
||||
mock_debouncer.clear()
|
||||
mqtt_client_mock.on_connect(None, None, None, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(None, None, None, 0)
|
||||
await mock_debouncer.wait()
|
||||
|
||||
mqtt_client_mock.subscribe.assert_called()
|
||||
@@ -1046,7 +1045,7 @@ async def test_restore_subscriptions_on_reconnect(
|
||||
assert ("test/state", 0) in help_all_subscribe_calls(mqtt_client_mock)
|
||||
|
||||
mqtt_client_mock.reset_mock()
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
|
||||
# Test to subscribe orther topic while the client is not connected
|
||||
await mqtt.async_subscribe(hass, "test/other", record_calls)
|
||||
@@ -1054,7 +1053,7 @@ async def test_restore_subscriptions_on_reconnect(
|
||||
assert ("test/other", 0) not in help_all_subscribe_calls(mqtt_client_mock)
|
||||
|
||||
mock_debouncer.clear()
|
||||
mqtt_client_mock.on_connect(None, None, None, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(None, None, None, 0)
|
||||
await mock_debouncer.wait()
|
||||
# Assert all subscriptions are performed at the broker
|
||||
assert ("test/state", 0) in help_all_subscribe_calls(mqtt_client_mock)
|
||||
@@ -1090,10 +1089,10 @@ async def test_restore_all_active_subscriptions_on_reconnect(
|
||||
unsub()
|
||||
assert mqtt_client_mock.unsubscribe.call_count == 0
|
||||
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
|
||||
mock_debouncer.clear()
|
||||
mqtt_client_mock.on_connect(None, None, None, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(None, None, None, 0)
|
||||
# wait for cooldown
|
||||
await mock_debouncer.wait()
|
||||
|
||||
@@ -1161,37 +1160,27 @@ async def test_logs_error_if_no_connect_broker(
|
||||
) -> None:
|
||||
"""Test for setup failure if connection to broker is missing."""
|
||||
mqtt_client_mock = setup_with_birth_msg_client_mock
|
||||
# test with reason code = 136 -> server unavailable
|
||||
mqtt_client_mock.on_disconnect(Mock(), None, None, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(
|
||||
Mock(),
|
||||
None,
|
||||
None,
|
||||
MockMqttReasonCode(value=136, is_failure=True, name="Server unavailable"),
|
||||
)
|
||||
# test with rc = 3 -> broker unavailable
|
||||
mqtt_client_mock.on_disconnect(Mock(), None, 0)
|
||||
mqtt_client_mock.on_connect(Mock(), None, None, 3)
|
||||
await hass.async_block_till_done()
|
||||
assert "Unable to connect to the MQTT broker: Server unavailable" in caplog.text
|
||||
assert (
|
||||
"Unable to connect to the MQTT broker: Connection Refused: broker unavailable."
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"reason_code",
|
||||
[
|
||||
MockMqttReasonCode(
|
||||
value=134, is_failure=True, name="Bad user name or password"
|
||||
),
|
||||
MockMqttReasonCode(value=135, is_failure=True, name="Not authorized"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("return_code", [4, 5])
|
||||
async def test_triggers_reauth_flow_if_auth_fails(
|
||||
hass: HomeAssistant,
|
||||
setup_with_birth_msg_client_mock: MqttMockPahoClient,
|
||||
reason_code: MockMqttReasonCode,
|
||||
return_code: int,
|
||||
) -> None:
|
||||
"""Test re-auth is triggered if authentication is failing."""
|
||||
mqtt_client_mock = setup_with_birth_msg_client_mock
|
||||
# test with rc = 4 -> CONNACK_REFUSED_NOT_AUTHORIZED and 5 -> CONNACK_REFUSED_BAD_USERNAME_PASSWORD
|
||||
mqtt_client_mock.on_disconnect(Mock(), None, 0, MockMqttReasonCode(), None)
|
||||
mqtt_client_mock.on_connect(Mock(), None, None, reason_code)
|
||||
mqtt_client_mock.on_disconnect(Mock(), None, 0)
|
||||
mqtt_client_mock.on_connect(Mock(), None, None, return_code)
|
||||
await hass.async_block_till_done()
|
||||
flows = hass.config_entries.flow.async_progress()
|
||||
assert len(flows) == 1
|
||||
@@ -1208,9 +1197,7 @@ async def test_handle_mqtt_on_callback(
|
||||
mqtt_client_mock = setup_with_birth_msg_client_mock
|
||||
with patch.object(mqtt_client_mock, "get_mid", return_value=100):
|
||||
# Simulate an ACK for mid == 100, this will call mqtt_mock._async_get_mid_future(mid)
|
||||
mqtt_client_mock.on_publish(
|
||||
mqtt_client_mock, None, 100, MockMqttReasonCode(), None
|
||||
)
|
||||
mqtt_client_mock.on_publish(mqtt_client_mock, None, 100)
|
||||
await hass.async_block_till_done()
|
||||
# Make sure the ACK has been received
|
||||
await hass.async_block_till_done()
|
||||
@@ -1232,7 +1219,7 @@ async def test_handle_mqtt_on_callback_after_cancellation(
|
||||
# Simulate the mid future getting a cancellation
|
||||
mqtt_mock()._async_get_mid_future(101).cancel()
|
||||
# Simulate an ACK for mid == 101, being received after the cancellation
|
||||
mqtt_client_mock.on_publish(mqtt_client_mock, None, 101, MockMqttReasonCode(), None)
|
||||
mqtt_client_mock.on_publish(mqtt_client_mock, None, 101)
|
||||
await hass.async_block_till_done()
|
||||
assert "No ACK from MQTT server" not in caplog.text
|
||||
assert "InvalidStateError" not in caplog.text
|
||||
@@ -1249,7 +1236,7 @@ async def test_handle_mqtt_on_callback_after_timeout(
|
||||
# Simulate the mid future getting a timeout
|
||||
mqtt_mock()._async_get_mid_future(101).set_exception(asyncio.TimeoutError)
|
||||
# Simulate an ACK for mid == 101, being received after the timeout
|
||||
mqtt_client_mock.on_publish(mqtt_client_mock, None, 101, MockMqttReasonCode(), None)
|
||||
mqtt_client_mock.on_publish(mqtt_client_mock, None, 101)
|
||||
await hass.async_block_till_done()
|
||||
assert "No ACK from MQTT server" not in caplog.text
|
||||
assert "InvalidStateError" not in caplog.text
|
||||
@@ -1271,7 +1258,7 @@ async def test_publish_error(
|
||||
with patch(
|
||||
"homeassistant.components.mqtt.async_client.AsyncMQTTClient"
|
||||
) as mock_client:
|
||||
mock_client().connect = lambda **kwargs: 1
|
||||
mock_client().connect = lambda *args: 1
|
||||
mock_client().publish().rc = 1
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
with pytest.raises(HomeAssistantError):
|
||||
@@ -1330,7 +1317,7 @@ async def test_handle_message_callback(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("mqtt_config_entry_data", "protocol", "clean_session"),
|
||||
("mqtt_config_entry_data", "protocol"),
|
||||
[
|
||||
(
|
||||
{
|
||||
@@ -1338,7 +1325,6 @@ async def test_handle_message_callback(
|
||||
CONF_PROTOCOL: "3.1",
|
||||
},
|
||||
3,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{
|
||||
@@ -1346,7 +1332,6 @@ async def test_handle_message_callback(
|
||||
CONF_PROTOCOL: "3.1.1",
|
||||
},
|
||||
4,
|
||||
True,
|
||||
),
|
||||
(
|
||||
{
|
||||
@@ -1354,72 +1339,22 @@ async def test_handle_message_callback(
|
||||
CONF_PROTOCOL: "5",
|
||||
},
|
||||
5,
|
||||
None,
|
||||
),
|
||||
],
|
||||
ids=["v3.1", "v3.1.1", "v5"],
|
||||
)
|
||||
async def test_setup_mqtt_client_clean_session_and_protocol(
|
||||
hass: HomeAssistant,
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
protocol: int,
|
||||
clean_session: bool | None,
|
||||
async def test_setup_mqtt_client_protocol(
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator, protocol: int
|
||||
) -> None:
|
||||
"""Test MQTT client clean_session and protocol setup."""
|
||||
"""Test MQTT client protocol setup."""
|
||||
with patch(
|
||||
"homeassistant.components.mqtt.async_client.AsyncMQTTClient"
|
||||
) as mock_client:
|
||||
await mqtt_mock_entry()
|
||||
|
||||
# check if clean_session was correctly
|
||||
assert mock_client.call_args[1]["clean_session"] == clean_session
|
||||
|
||||
# check if protocol setup was correctly
|
||||
assert mock_client.call_args[1]["protocol"] == protocol
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("mqtt_config_entry_data", "connect_args"),
|
||||
[
|
||||
(
|
||||
{
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
CONF_PROTOCOL: "3.1",
|
||||
},
|
||||
call(host="mock-broker", port=1883, keepalive=60, clean_start=3),
|
||||
),
|
||||
(
|
||||
{
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
CONF_PROTOCOL: "3.1.1",
|
||||
},
|
||||
call(host="mock-broker", port=1883, keepalive=60, clean_start=3),
|
||||
),
|
||||
(
|
||||
{
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
CONF_PROTOCOL: "5",
|
||||
},
|
||||
call(host="mock-broker", port=1883, keepalive=60, clean_start=True),
|
||||
),
|
||||
],
|
||||
ids=["v3.1", "v3.1.1", "v5"],
|
||||
)
|
||||
async def test_setup_mqtt_client_clean_start(
|
||||
hass: HomeAssistant,
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
connect_args: tuple[Any],
|
||||
) -> None:
|
||||
"""Test MQTT client protocol connects with `clean_start` set correctly."""
|
||||
await mqtt_mock_entry()
|
||||
|
||||
# check if clean_start was set correctly
|
||||
assert len(mqtt_client_mock.connect.mock_calls) == 1
|
||||
assert mqtt_client_mock.connect.mock_calls[0] == connect_args
|
||||
|
||||
|
||||
@patch("homeassistant.components.mqtt.client.TIMEOUT_ACK", 0.2)
|
||||
async def test_handle_mqtt_timeout_on_callback(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, mock_debouncer: asyncio.Event
|
||||
@@ -1453,7 +1388,7 @@ async def test_handle_mqtt_timeout_on_callback(
|
||||
mock_client.connect = MagicMock(
|
||||
return_value=0,
|
||||
side_effect=lambda *args, **kwargs: hass.loop.call_soon_threadsafe(
|
||||
mock_client.on_connect, mock_client, None, 0, MockMqttReasonCode()
|
||||
mock_client.on_connect, mock_client, None, 0, 0, 0
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1842,12 +1777,12 @@ async def test_mqtt_subscribes_topics_on_connect(
|
||||
await mqtt.async_subscribe(hass, "still/pending", record_calls, 1)
|
||||
await mock_debouncer.wait()
|
||||
|
||||
mqtt_client_mock.on_disconnect(Mock(), None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(Mock(), None, 0)
|
||||
|
||||
mqtt_client_mock.reset_mock()
|
||||
|
||||
mock_debouncer.clear()
|
||||
mqtt_client_mock.on_connect(Mock(), None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(Mock(), None, 0, 0)
|
||||
await mock_debouncer.wait()
|
||||
|
||||
subscribe_calls = help_all_subscribe_calls(mqtt_client_mock)
|
||||
@@ -1902,12 +1837,12 @@ async def test_mqtt_subscribes_wildcard_topics_in_correct_order(
|
||||
# Assert the initial wildcard topic subscription order
|
||||
_assert_subscription_order()
|
||||
|
||||
mqtt_client_mock.on_disconnect(Mock(), None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(Mock(), None, 0)
|
||||
|
||||
mqtt_client_mock.reset_mock()
|
||||
|
||||
mock_debouncer.clear()
|
||||
mqtt_client_mock.on_connect(Mock(), None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(Mock(), None, 0, 0)
|
||||
await mock_debouncer.wait()
|
||||
|
||||
# Assert the wildcard topic subscription order after a reconnect
|
||||
@@ -1933,12 +1868,12 @@ async def test_mqtt_discovery_not_subscribes_when_disabled(
|
||||
assert (f"homeassistant/{component}/+/config", 0) not in subscribe_calls
|
||||
assert (f"homeassistant/{component}/+/+/config", 0) not in subscribe_calls
|
||||
|
||||
mqtt_client_mock.on_disconnect(Mock(), None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(Mock(), None, 0)
|
||||
|
||||
mqtt_client_mock.reset_mock()
|
||||
|
||||
mock_debouncer.clear()
|
||||
mqtt_client_mock.on_connect(Mock(), None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(Mock(), None, 0, 0)
|
||||
await mock_debouncer.wait()
|
||||
|
||||
subscribe_calls = help_all_subscribe_calls(mqtt_client_mock)
|
||||
@@ -2033,7 +1968,7 @@ async def test_auto_reconnect(
|
||||
mqtt_client_mock.reconnect.reset_mock()
|
||||
|
||||
mqtt_client_mock.disconnect()
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mqtt_client_mock.reconnect.side_effect = exception("foo")
|
||||
@@ -2054,7 +1989,7 @@ async def test_auto_reconnect(
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
||||
|
||||
mqtt_client_mock.disconnect()
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
async_fire_time_changed(
|
||||
@@ -2096,7 +2031,7 @@ async def test_server_sock_connect_and_disconnect(
|
||||
mqtt_client_mock.loop_misc.return_value = paho_mqtt.MQTT_ERR_CONN_LOST
|
||||
mqtt_client_mock.on_socket_unregister_write(mqtt_client_mock, None, client)
|
||||
mqtt_client_mock.on_socket_close(mqtt_client_mock, None, client)
|
||||
mqtt_client_mock.on_disconnect(mqtt_client_mock, None, None, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(mqtt_client_mock, None, client)
|
||||
await hass.async_block_till_done()
|
||||
mock_debouncer.clear()
|
||||
unsub()
|
||||
@@ -2147,7 +2082,7 @@ async def test_server_sock_buffer_size_with_websocket(
|
||||
client.setblocking(False)
|
||||
server.setblocking(False)
|
||||
|
||||
class FakeWebsocket(paho_mqtt._WebsocketWrapper):
|
||||
class FakeWebsocket(paho_mqtt.WebsocketWrapper):
|
||||
def _do_handshake(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
@@ -2234,4 +2169,4 @@ async def test_loop_write_failure(
|
||||
# Final for the disconnect callback
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert "Error returned from MQTT server: The connection was lost." in caplog.text
|
||||
assert "Disconnected from MQTT server test-broker:1883" in caplog.text
|
||||
|
||||
@@ -28,7 +28,7 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
from homeassistant.helpers.service_info.hassio import HassioServiceInfo
|
||||
|
||||
from tests.common import MockConfigEntry, MockMqttReasonCode
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
|
||||
|
||||
ADD_ON_DISCOVERY_INFO = {
|
||||
@@ -143,16 +143,16 @@ def mock_try_connection_success() -> Generator[MqttMockPahoClient]:
|
||||
|
||||
def loop_start():
|
||||
"""Simulate connect on loop start."""
|
||||
mock_client().on_connect(mock_client, None, None, MockMqttReasonCode(), None)
|
||||
mock_client().on_connect(mock_client, None, None, 0)
|
||||
|
||||
def _subscribe(topic, qos=0):
|
||||
mid = get_mid()
|
||||
mock_client().on_subscribe(mock_client, 0, mid, [MockMqttReasonCode()], None)
|
||||
mock_client().on_subscribe(mock_client, 0, mid)
|
||||
return (0, mid)
|
||||
|
||||
def _unsubscribe(topic):
|
||||
mid = get_mid()
|
||||
mock_client().on_unsubscribe(mock_client, 0, mid, [MockMqttReasonCode()], None)
|
||||
mock_client().on_unsubscribe(mock_client, 0, mid)
|
||||
return (0, mid)
|
||||
|
||||
with patch(
|
||||
|
||||
@@ -45,7 +45,6 @@ from tests.common import (
|
||||
MockConfigEntry,
|
||||
MockEntity,
|
||||
MockEntityPlatform,
|
||||
MockMqttReasonCode,
|
||||
async_fire_mqtt_message,
|
||||
async_fire_time_changed,
|
||||
mock_restore_cache,
|
||||
@@ -1573,7 +1572,6 @@ async def test_subscribe_connection_status(
|
||||
setup_with_birth_msg_client_mock: MqttMockPahoClient,
|
||||
) -> None:
|
||||
"""Test connextion status subscription."""
|
||||
|
||||
mqtt_client_mock = setup_with_birth_msg_client_mock
|
||||
mqtt_connected_calls_callback: list[bool] = []
|
||||
mqtt_connected_calls_async: list[bool] = []
|
||||
@@ -1591,7 +1589,7 @@ async def test_subscribe_connection_status(
|
||||
assert mqtt.is_connected(hass) is True
|
||||
|
||||
# Mock disconnect status
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
await hass.async_block_till_done()
|
||||
assert mqtt.is_connected(hass) is False
|
||||
|
||||
@@ -1605,12 +1603,12 @@ async def test_subscribe_connection_status(
|
||||
|
||||
# Mock connect status
|
||||
mock_debouncer.clear()
|
||||
mqtt_client_mock.on_connect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(None, None, 0, 0)
|
||||
await mock_debouncer.wait()
|
||||
assert mqtt.is_connected(hass) is True
|
||||
|
||||
# Mock disconnect status
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
await hass.async_block_till_done()
|
||||
assert mqtt.is_connected(hass) is False
|
||||
|
||||
@@ -1620,7 +1618,7 @@ async def test_subscribe_connection_status(
|
||||
|
||||
# Mock connect status
|
||||
mock_debouncer.clear()
|
||||
mqtt_client_mock.on_connect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(None, None, 0, 0)
|
||||
await mock_debouncer.wait()
|
||||
assert mqtt.is_connected(hass) is True
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ from homeassistant.const import STATE_UNAVAILABLE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
from tests.common import MockMqttReasonCode, async_fire_mqtt_message
|
||||
from tests.common import async_fire_mqtt_message
|
||||
from tests.typing import MqttMockHAClient, MqttMockPahoClient, WebSocketGenerator
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
@@ -165,7 +165,7 @@ async def help_test_availability_when_connection_lost(
|
||||
|
||||
# Disconnected from MQTT server -> state changed to unavailable
|
||||
mqtt_mock.connected = False
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
@@ -174,7 +174,7 @@ async def help_test_availability_when_connection_lost(
|
||||
|
||||
# Reconnected to MQTT server -> state still unavailable
|
||||
mqtt_mock.connected = True
|
||||
mqtt_client_mock.on_connect(None, None, None, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(None, None, None, 0)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
@@ -226,7 +226,7 @@ async def help_test_deep_sleep_availability_when_connection_lost(
|
||||
|
||||
# Disconnected from MQTT server -> state changed to unavailable
|
||||
mqtt_mock.connected = False
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
@@ -235,7 +235,7 @@ async def help_test_deep_sleep_availability_when_connection_lost(
|
||||
|
||||
# Reconnected to MQTT server -> state no longer unavailable
|
||||
mqtt_mock.connected = True
|
||||
mqtt_client_mock.on_connect(None, None, None, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(None, None, None, 0)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
@@ -478,7 +478,7 @@ async def help_test_availability_poll_state(
|
||||
|
||||
# Disconnected from MQTT server
|
||||
mqtt_mock.connected = False
|
||||
mqtt_client_mock.on_disconnect(None, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_disconnect(None, None, 0)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
@@ -486,7 +486,7 @@ async def help_test_availability_poll_state(
|
||||
|
||||
# Reconnected to MQTT server
|
||||
mqtt_mock.connected = True
|
||||
mqtt_client_mock.on_connect(None, None, None, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(None, None, None, 0)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
@@ -120,7 +120,6 @@ from .common import ( # noqa: E402, isort:skip
|
||||
CLIENT_ID,
|
||||
INSTANCES,
|
||||
MockConfigEntry,
|
||||
MockMqttReasonCode,
|
||||
MockUser,
|
||||
async_fire_mqtt_message,
|
||||
async_test_home_assistant,
|
||||
@@ -972,23 +971,17 @@ def mqtt_client_mock(hass: HomeAssistant) -> Generator[MqttMockPahoClient]:
|
||||
def _async_fire_mqtt_message(topic, payload, qos, retain):
|
||||
async_fire_mqtt_message(hass, topic, payload or b"", qos, retain)
|
||||
mid = get_mid()
|
||||
hass.loop.call_soon(
|
||||
mock_client.on_publish, Mock(), 0, mid, MockMqttReasonCode(), None
|
||||
)
|
||||
hass.loop.call_soon(mock_client.on_publish, 0, 0, mid)
|
||||
return FakeInfo(mid)
|
||||
|
||||
def _subscribe(topic, qos=0):
|
||||
mid = get_mid()
|
||||
hass.loop.call_soon(
|
||||
mock_client.on_subscribe, Mock(), 0, mid, [MockMqttReasonCode()], None
|
||||
)
|
||||
hass.loop.call_soon(mock_client.on_subscribe, 0, 0, mid)
|
||||
return (0, mid)
|
||||
|
||||
def _unsubscribe(topic):
|
||||
mid = get_mid()
|
||||
hass.loop.call_soon(
|
||||
mock_client.on_unsubscribe, Mock(), 0, mid, [MockMqttReasonCode()], None
|
||||
)
|
||||
hass.loop.call_soon(mock_client.on_unsubscribe, 0, 0, mid)
|
||||
return (0, mid)
|
||||
|
||||
def _connect(*args, **kwargs):
|
||||
@@ -997,7 +990,7 @@ def mqtt_client_mock(hass: HomeAssistant) -> Generator[MqttMockPahoClient]:
|
||||
# the behavior.
|
||||
mock_client.reconnect()
|
||||
hass.loop.call_soon_threadsafe(
|
||||
mock_client.on_connect, mock_client, None, 0, MockMqttReasonCode()
|
||||
mock_client.on_connect, mock_client, None, 0, 0, 0
|
||||
)
|
||||
mock_client.on_socket_open(
|
||||
mock_client, None, Mock(fileno=Mock(return_value=-1))
|
||||
@@ -1074,7 +1067,7 @@ async def _mqtt_mock_entry(
|
||||
|
||||
# connected set to True to get a more realistic behavior when subscribing
|
||||
mock_mqtt_instance.connected = True
|
||||
mqtt_client_mock.on_connect(mqtt_client_mock, None, 0, MockMqttReasonCode())
|
||||
mqtt_client_mock.on_connect(mqtt_client_mock, None, 0, 0, 0)
|
||||
|
||||
async_dispatcher_send(hass, mqtt.MQTT_CONNECTION_STATE, True)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
Reference in New Issue
Block a user