Browse Source

fix `ValueError: too many values to unpack` when connecting to MQTT broker via IPv6

https://github.com/fphammerle/switchbot-mqtt/issues/42
Fabian Peter Hammerle 1 year ago
parent
commit
659eef7697
3 changed files with 31 additions and 5 deletions
  1. 3 0
      CHANGELOG.md
  2. 10 2
      switchbot_mqtt/__init__.py
  3. 18 3
      tests/test_mqtt.py

+ 3 - 0
CHANGELOG.md

@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ## [Unreleased]
+### Fixed
+- `ValueError: too many values to unpack` when connecting to MQTT broker via IPv6
+  (https://github.com/fphammerle/switchbot-mqtt/issues/42)
 
 ## [3.2.0] - 2022-04-18
 ### Added

+ 10 - 2
switchbot_mqtt/__init__.py

@@ -17,6 +17,7 @@
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 import logging
+import socket
 import typing
 
 import paho.mqtt.client
@@ -36,8 +37,15 @@ def _mqtt_on_connect(
     # pylint: disable=unused-argument; callback
     # https://github.com/eclipse/paho.mqtt.python/blob/v1.5.0/src/paho/mqtt/client.py#L441
     assert return_code == 0, return_code  # connection accepted
-    mqtt_broker_host, mqtt_broker_port = mqtt_client.socket().getpeername()
-    _LOGGER.debug("connected to MQTT broker %s:%d", mqtt_broker_host, mqtt_broker_port)
+    mqtt_broker_host, mqtt_broker_port, *_ = mqtt_client.socket().getpeername()
+    # https://www.rfc-editor.org/rfc/rfc5952#section-6
+    _LOGGER.debug(
+        "connected to MQTT broker %s:%d",
+        f"[{mqtt_broker_host}]"
+        if mqtt_client.socket().family == socket.AF_INET6
+        else mqtt_broker_host,
+        mqtt_broker_port,
+    )
     _ButtonAutomator.mqtt_subscribe(mqtt_client=mqtt_client, settings=userdata)
     _CurtainMotor.mqtt_subscribe(mqtt_client=mqtt_client, settings=userdata)
 

+ 18 - 3
tests/test_mqtt.py

@@ -17,6 +17,7 @@
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 import logging
+import socket
 import typing
 import unittest.mock
 
@@ -35,9 +36,23 @@ from switchbot_mqtt._utils import _MQTTTopicLevel, _MQTTTopicPlaceholder
 # pylint: disable=too-many-arguments; these are tests, no API
 
 
-def test__mqtt_on_connect(caplog: _pytest.logging.LogCaptureFixture) -> None:
+@pytest.mark.parametrize(
+    ("socket_family", "peername", "peername_log"),
+    [
+        (socket.AF_INET, ("mqtt-broker.local", 1883), "mqtt-broker.local:1883"),
+        # https://github.com/fphammerle/switchbot-mqtt/issues/42#issuecomment-1173909335
+        (socket.AF_INET6, ("::1", 1883, 0, 0), "[::1]:1883"),
+    ],
+)
+def test__mqtt_on_connect(
+    caplog: _pytest.logging.LogCaptureFixture,
+    socket_family: int,  # socket.AddressFamily,
+    peername: typing.Tuple[typing.Union[str, int]],
+    peername_log: str,
+) -> None:
     mqtt_client = unittest.mock.MagicMock()
-    mqtt_client.socket().getpeername.return_value = ("mqtt-broker.local", 1883)
+    mqtt_client.socket().family = socket_family
+    mqtt_client.socket().getpeername.return_value = peername
     with caplog.at_level(logging.DEBUG):
         switchbot_mqtt._mqtt_on_connect(
             mqtt_client,
@@ -60,7 +75,7 @@ def test__mqtt_on_connect(caplog: _pytest.logging.LogCaptureFixture) -> None:
         (
             "switchbot_mqtt",
             logging.DEBUG,
-            "connected to MQTT broker mqtt-broker.local:1883",
+            "connected to MQTT broker " + peername_log,
         ),
         (
             "switchbot_mqtt._actors.base",