Files
ha-deconz-bridge/tests/test_ha.py
T
2026-05-30 15:44:40 +00:00

126 lines
4.4 KiB
Python

from __future__ import annotations
import json
from ha_deconz_bridge.ha import HomeAssistantBridge
from ha_deconz_bridge.lights import ChannelSpec, ControllerModeSpec, ControllerSpec, VirtualLightSpec
from ha_deconz_bridge.light import VirtualLightState
from ha_deconz_bridge.color import Color
class FakeMQTTClient:
def __init__(self) -> None:
self.connected = False
self.on_connect = None
self.on_message = None
self.published: list[tuple[str, str, bool]] = []
self.subscriptions: list[str] = []
def username_pw_set(self, username, password) -> None:
self.username = username
self.password = password
def connect(self, host: str, port: int, keepalive: int) -> None:
self.host = host
self.port = port
self.keepalive = keepalive
def loop_start(self) -> None:
self.connected = True
if self.on_connect is not None:
self.on_connect(self, None, None, 0)
def loop_stop(self) -> None:
self.connected = False
def disconnect(self) -> None:
self.connected = False
def publish(self, topic: str, payload: str, retain: bool = False):
if not self.connected:
raise RuntimeError("publish before MQTT connect")
self.published.append((topic, payload, retain))
def subscribe(self, topic: str) -> None:
if not self.connected:
raise RuntimeError("subscribe before MQTT connect")
self.subscriptions.append(topic)
def test_bridge_waits_for_connect_before_discovery(settings, rgb_light_spec) -> None:
mqtt = FakeMQTTClient()
bridge = HomeAssistantBridge(settings, mqtt_client=mqtt)
bridge.start(on_command=lambda event: None)
bridge.publish_discovery(rgb_light_spec)
bridge.publish_state(
rgb_light_spec,
VirtualLightState(
on=True,
color=rgb_light_spec.controllers["1"].modes["rgb"].channels["r"].color,
ha_mode="rgb",
brightness=128,
exact_chroma_match=True,
),
)
assert mqtt.published[0][0] == "homeassistant/light/rgb_light/config"
assert json.loads(mqtt.published[0][1])["schema"] == "json"
assert json.loads(mqtt.published[0][1])["name"] == "rgb_light"
assert mqtt.subscriptions == ["ha-deconz-bridge/light/rgb_light/set"]
def test_bridge_sanitizes_mqtt_object_id_for_discovery_topics(settings) -> None:
mqtt = FakeMQTTClient()
bridge = HomeAssistantBridge(settings, mqtt_client=mqtt)
bridge.start(on_command=lambda event: None)
spec = VirtualLightSpec(
name="Example Light North",
supported_color_modes=("brightness",),
controllers={
"example_controller": ControllerSpec(
zigbee_id="example_controller",
name="Example controller",
modes={
"brightness": ControllerModeSpec(
name="brightness",
channels={
"w": ChannelSpec(
"w",
Color.from_color_temp(182, brightness=1.0),
semantic_label="color_temp",
)
},
)
},
)
},
)
bridge.publish_discovery(spec)
assert mqtt.published[0][0] == "homeassistant/light/Example_Light_North/config"
payload = json.loads(mqtt.published[0][1])
assert payload["name"] == "Example Light North"
assert payload["unique_id"] == "Example_Light_North"
assert payload["device"]["identifiers"] == ["ha-deconz-bridge:Example_Light_North"]
assert payload["device"]["name"] == "HA deCONZ Bridge: Example Light North"
assert payload["command_topic"] == "ha-deconz-bridge/light/Example_Light_North/set"
assert payload["state_topic"] == "ha-deconz-bridge/light/Example_Light_North/state"
assert mqtt.subscriptions == ["ha-deconz-bridge/light/Example_Light_North/set"]
def test_bridge_resubscribes_to_command_topics_on_reconnect(settings, rgb_light_spec) -> None:
mqtt = FakeMQTTClient()
bridge = HomeAssistantBridge(settings, mqtt_client=mqtt)
bridge.start(on_command=lambda event: None)
bridge.publish_discovery(rgb_light_spec)
mqtt.loop_stop()
mqtt.loop_start()
assert mqtt.subscriptions == [
"ha-deconz-bridge/light/rgb_light/set",
"ha-deconz-bridge/light/rgb_light/set",
]