Skip to content
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

Change virtual device detection #151

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
2 changes: 1 addition & 1 deletion src/abbfreeathome/bin/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ class Interface(enum.Enum):
WIRELESS_RF = "RF"
HUE = "hue"
SONOS = "sonos"
VIRTUAL_DEVICE = "vdev:[email protected]"
VIRTUAL_DEVICE = "VD"
5 changes: 5 additions & 0 deletions src/abbfreeathome/devices/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ def room_name(self) -> str | None:
"""Get the room name of the device."""
return self._room_name

@property
def is_virtual(self) -> bool | None:
"""Get the virtual-status of the device."""
return self.device_id[0:4] == "6000"

def get_input_by_pairing(self, pairing: Pairing) -> tuple[str, Any]:
"""Get the channel input by pairing id."""
for _input_id, _input in self._inputs.items():
Expand Down
3 changes: 3 additions & 0 deletions src/abbfreeathome/freeathome.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ async def get_devices_by_function(self, function: Function) -> list[dict]:
"""Get the list of devices by function."""
_devices = []
for _device_key, _device in (await self.get_config()).get("devices").items():
if _device_key[0:4] == "6000":
_device["interface"] = "VD"

# Filter by interface if provided
if self._interfaces and _device.get("interface") not in [
interface.value for interface in self._interfaces
Expand Down
96 changes: 94 additions & 2 deletions tests/test_freeathome.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,60 @@ def api_mock():
},
},
},
"60002AE2F1BE": {
"nativeId": "abcd12350",
"deviceId": "0004",
"displayName": "MyVirtualDoorSensor",
"unresponsive": False,
"unresponsiveCounter": 0,
"defect": False,
"channels": {
"ch0000": {
"displayName": "MyVirtualDoorSensor",
"floor": "01",
"room": "01",
"functionID": "f",
"inputs": {},
"outputs": {"odp000c": {"pairingID": 53, "value": ""}},
"parameters": {"par0010": "1"},
"selectedIcon": "51",
}
},
"parameters": {},
},
"60005D808C54": {
"floor": "01",
"room": "01",
"nativeId": "virtual-switch-sleep",
"interface": "vdev:[email protected]",
"deviceId": "0001",
"displayName": "Sleepmode",
"unresponsive": False,
"unresponsiveCounter": 0,
"defect": False,
"channels": {
"ch0000": {
"displayName": "Sleepmode",
"floor": "01",
"room": "01",
"functionID": "7",
"inputs": {
"idp0000": {"pairingID": 1, "value": "1"},
"idp0001": {"pairingID": 2, "value": ""},
"idp0002": {"pairingID": 3, "value": ""},
"idp0003": {"pairingID": 4, "value": ""},
"idp0004": {"pairingID": 6, "value": ""},
},
"outputs": {
"odp0000": {"pairingID": 256, "value": "0"},
"odp0001": {"pairingID": 257, "value": "0"},
},
"parameters": {"par0015": "60", "par0014": "1"},
"selectedIcon": "0B",
}
},
"parameters": {},
},
},
}
return api
Expand All @@ -243,15 +297,30 @@ def api_mock():
def freeathome(api_mock):
"""Create the FreeAtHome fixture."""
return FreeAtHome(
api=api_mock, interfaces=[Interface.WIRED_BUS], include_orphan_channels=False
api=api_mock,
interfaces=[Interface.WIRED_BUS],
include_orphan_channels=False,
)


@pytest.fixture
def freeathome_orphans(api_mock):
"""Create the FreeAtHome fixture."""
return FreeAtHome(
api=api_mock, interfaces=[Interface.WIRED_BUS], include_orphan_channels=True
api=api_mock,
interfaces=[Interface.WIRED_BUS],
include_orphan_channels=True,
)


# This can be removed, when ABB fixes the bug
@pytest.fixture
def freeathome_virtuals(api_mock):
"""Create the FreeAtHome fixture."""
return FreeAtHome(
api=api_mock,
interfaces=[Interface.VIRTUAL_DEVICE],
include_orphan_channels=False,
)


Expand Down Expand Up @@ -347,6 +416,7 @@ async def test_load_devices(freeathome):
assert devices[device_key].channel_name == "Study Area Light"
assert devices[device_key].floor_name == "Ground Floor"
assert devices[device_key].room_name == "Living Room"
assert devices[device_key].is_virtual is False

# Unload a single device and test it's been removed
freeathome.unload_device_by_device_serial(device_serial="ABB7F62F6C0B")
Expand Down Expand Up @@ -375,6 +445,28 @@ async def test_load_devices_with_orphans(freeathome_orphans):
assert devices[device_key].room_name is None


@pytest.mark.asyncio
async def test_load_devices_with_virtuals(freeathome_virtuals):
"""Test the load_devices function."""
await freeathome_virtuals.load_devices()

# Get the dict of devices
devices = freeathome_virtuals.get_devices()

# Verify that the devices are loaded correctly
assert len(devices) == 2

# Check a single virtual device
device_key = "60005D808C54/ch0000"
assert device_key in devices
assert isinstance(devices[device_key], SwitchActuator)
assert devices[device_key].device_name == "Sleepmode"
assert devices[device_key].channel_name == "Sleepmode"
assert devices[device_key].floor_name == "Ground Floor"
assert devices[device_key].room_name == "Living Room"
assert devices[device_key].is_virtual is True


@pytest.mark.asyncio
async def test_ws_close(freeathome, api_mock):
"Test the ws_close function."
Expand Down
Loading