diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index b98fe990fe8..090d9cdfa73 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -1206,20 +1206,29 @@ async def websocket_subscribe(hass, connection, msg): async def forward_messages(mqttmsg: ReceiveMessage): """Forward events to websocket.""" + try: + payload = cast(bytes, mqttmsg.payload).decode( + DEFAULT_ENCODING + ) # not str because encoding is set to None + except (AttributeError, UnicodeDecodeError): + # Convert non UTF-8 payload to a string presentation + payload = str(mqttmsg.payload) + connection.send_message( websocket_api.event_message( msg["id"], { "topic": mqttmsg.topic, - "payload": mqttmsg.payload, + "payload": payload, "qos": mqttmsg.qos, "retain": mqttmsg.retain, }, ) ) + # Perform UTF-8 decoding directly in callback routine connection.subscriptions[msg["id"]] = await async_subscribe( - hass, msg["topic"], forward_messages + hass, msg["topic"], forward_messages, encoding=None ) connection.send_message(websocket_api.result_message(msg["id"])) diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index b770122d39a..44803f2a5f6 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -1647,6 +1647,7 @@ async def test_mqtt_ws_subscription(hass, hass_ws_client, mqtt_mock): async_fire_mqtt_message(hass, "test-topic", "test1") async_fire_mqtt_message(hass, "test-topic", "test2") + async_fire_mqtt_message(hass, "test-topic", b"\xDE\xAD\xBE\xEF") response = await client.receive_json() assert response["event"]["topic"] == "test-topic" @@ -1656,6 +1657,10 @@ async def test_mqtt_ws_subscription(hass, hass_ws_client, mqtt_mock): assert response["event"]["topic"] == "test-topic" assert response["event"]["payload"] == "test2" + response = await client.receive_json() + assert response["event"]["topic"] == "test-topic" + assert response["event"]["payload"] == "b'\\xde\\xad\\xbe\\xef'" + # Unsubscribe await client.send_json({"id": 8, "type": "unsubscribe_events", "subscription": 5}) response = await client.receive_json()