Skip to content
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
42 changes: 19 additions & 23 deletions homeassistant/components/hunterdouglas_powerview/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging

from aiopvapi.helpers.aiorequest import AioRequest
from aiopvapi.helpers.api_base import ApiEntryPoint
from aiopvapi.helpers.constants import ATTR_ID
from aiopvapi.helpers.tools import base64_to_unicode
from aiopvapi.rooms import Rooms
Expand All @@ -20,7 +21,9 @@
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import (
API_PATH_FWVERSION,
COORDINATOR,
DEFAULT_LEGACY_MAINPROCESSOR,
DEVICE_FIRMWARE,
DEVICE_INFO,
DEVICE_MAC_ADDRESS,
Expand All @@ -29,24 +32,18 @@
DEVICE_REVISION,
DEVICE_SERIAL_NUMBER,
DOMAIN,
FIRMWARE_BUILD,
FIRMWARE_IN_USERDATA,
FIRMWARE_SUB_REVISION,
FIRMWARE,
FIRMWARE_MAINPROCESSOR,
FIRMWARE_NAME,
FIRMWARE_REVISION,
HUB_EXCEPTIONS,
HUB_NAME,
LEGACY_DEVICE_BUILD,
LEGACY_DEVICE_MODEL,
LEGACY_DEVICE_REVISION,
LEGACY_DEVICE_SUB_REVISION,
MAC_ADDRESS_IN_USERDATA,
MAINPROCESSOR_IN_USERDATA_FIRMWARE,
MODEL_IN_MAINPROCESSOR,
PV_API,
PV_ROOM_DATA,
PV_SCENE_DATA,
PV_SHADE_DATA,
PV_SHADES,
REVISION_IN_MAINPROCESSOR,
ROOM_DATA,
SCENE_DATA,
SERIAL_NUMBER_IN_USERDATA,
Expand Down Expand Up @@ -137,26 +134,25 @@ async def async_get_device_info(pv_request):
resources = await userdata.get_resources()
userdata_data = resources[USER_DATA]

if FIRMWARE_IN_USERDATA in userdata_data:
main_processor_info = userdata_data[FIRMWARE_IN_USERDATA][
MAINPROCESSOR_IN_USERDATA_FIRMWARE
]
else:
if FIRMWARE in userdata_data:
main_processor_info = userdata_data[FIRMWARE][FIRMWARE_MAINPROCESSOR]
elif userdata_data:
# Legacy devices
main_processor_info = {
REVISION_IN_MAINPROCESSOR: LEGACY_DEVICE_REVISION,
FIRMWARE_SUB_REVISION: LEGACY_DEVICE_SUB_REVISION,
FIRMWARE_BUILD: LEGACY_DEVICE_BUILD,
MODEL_IN_MAINPROCESSOR: LEGACY_DEVICE_MODEL,
}
fwversion = ApiEntryPoint(pv_request, API_PATH_FWVERSION)
resources = await fwversion.get_resources()

if FIRMWARE in resources:
main_processor_info = resources[FIRMWARE][FIRMWARE_MAINPROCESSOR]
else:
main_processor_info = DEFAULT_LEGACY_MAINPROCESSOR

return {
DEVICE_NAME: base64_to_unicode(userdata_data[HUB_NAME]),
DEVICE_MAC_ADDRESS: userdata_data[MAC_ADDRESS_IN_USERDATA],
DEVICE_SERIAL_NUMBER: userdata_data[SERIAL_NUMBER_IN_USERDATA],
DEVICE_REVISION: main_processor_info[REVISION_IN_MAINPROCESSOR],
DEVICE_REVISION: main_processor_info[FIRMWARE_REVISION],
DEVICE_FIRMWARE: main_processor_info,
DEVICE_MODEL: main_processor_info[MODEL_IN_MAINPROCESSOR],
DEVICE_MODEL: main_processor_info[FIRMWARE_NAME],
}


Expand Down
21 changes: 14 additions & 7 deletions homeassistant/components/hunterdouglas_powerview/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,11 @@

MAC_ADDRESS_IN_USERDATA = "macAddress"
SERIAL_NUMBER_IN_USERDATA = "serialNumber"
FIRMWARE_IN_USERDATA = "firmware"
MAINPROCESSOR_IN_USERDATA_FIRMWARE = "mainProcessor"
REVISION_IN_MAINPROCESSOR = "revision"
MODEL_IN_MAINPROCESSOR = "name"
HUB_NAME = "hubName"

FIRMWARE_IN_SHADE = "firmware"

FIRMWARE = "firmware"
FIRMWARE_MAINPROCESSOR = "mainProcessor"
FIRMWARE_NAME = "name"
FIRMWARE_REVISION = "revision"
FIRMWARE_SUB_REVISION = "subRevision"
FIRMWARE_BUILD = "build"
Expand Down Expand Up @@ -70,4 +67,14 @@
LEGACY_DEVICE_SUB_REVISION = 1
LEGACY_DEVICE_REVISION = 0
LEGACY_DEVICE_BUILD = 0
LEGACY_DEVICE_MODEL = "PV Hub1.0"
LEGACY_DEVICE_MODEL = "PowerView Hub"

DEFAULT_LEGACY_MAINPROCESSOR = {
FIRMWARE_REVISION: LEGACY_DEVICE_REVISION,
FIRMWARE_SUB_REVISION: LEGACY_DEVICE_SUB_REVISION,
FIRMWARE_BUILD: LEGACY_DEVICE_BUILD,
FIRMWARE_NAME: LEGACY_DEVICE_MODEL,
}


API_PATH_FWVERSION = "api/fwversion"
19 changes: 10 additions & 9 deletions homeassistant/components/hunterdouglas_powerview/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
DEVICE_NAME,
DEVICE_SERIAL_NUMBER,
DOMAIN,
FIRMWARE,
FIRMWARE_BUILD,
FIRMWARE_IN_SHADE,
FIRMWARE_REVISION,
FIRMWARE_SUB_REVISION,
MANUFACTURER,
Expand Down Expand Up @@ -71,20 +71,21 @@ def device_info(self):
"name": self._shade_name,
"suggested_area": self._room_name,
"manufacturer": MANUFACTURER,
"model": self._shade.raw_data[ATTR_TYPE],
"via_device": (DOMAIN, self._device_info[DEVICE_SERIAL_NUMBER]),
}

if FIRMWARE_IN_SHADE not in self._shade.raw_data:
for shade in self._shade.shade_types:
if shade.shade_type == device_info["model"]:
Comment thread
bdraco marked this conversation as resolved.
device_info["model"] = shade.description
break

if FIRMWARE not in self._shade.raw_data:
return device_info

firmware = self._shade.raw_data[FIRMWARE_IN_SHADE]
firmware = self._shade.raw_data[FIRMWARE]
sw_version = f"{firmware[FIRMWARE_REVISION]}.{firmware[FIRMWARE_SUB_REVISION]}.{firmware[FIRMWARE_BUILD]}"
model = self._shade.raw_data[ATTR_TYPE]
for shade in self._shade.shade_types:
if shade.shade_type == model:
model = shade.description
break

device_info["sw_version"] = sw_version
device_info["model"] = model

return device_info
75 changes: 72 additions & 3 deletions tests/components/hunterdouglas_powerview/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,34 @@ def _get_mock_powerview_userdata(userdata=None, get_resources=None):
if not userdata:
userdata = json.loads(load_fixture("hunterdouglas_powerview/userdata.json"))
if get_resources:
type(mock_powerview_userdata).get_resources = AsyncMock(
mock_powerview_userdata.get_resources = AsyncMock(side_effect=get_resources)
else:
mock_powerview_userdata.get_resources = AsyncMock(return_value=userdata)
return mock_powerview_userdata


def _get_mock_powerview_legacy_userdata(userdata=None, get_resources=None):
mock_powerview_userdata_legacy = MagicMock()
if not userdata:
userdata = json.loads(load_fixture("hunterdouglas_powerview/userdata_v1.json"))
if get_resources:
mock_powerview_userdata_legacy.get_resources = AsyncMock(
side_effect=get_resources
)
else:
type(mock_powerview_userdata).get_resources = AsyncMock(return_value=userdata)
return mock_powerview_userdata
mock_powerview_userdata_legacy.get_resources = AsyncMock(return_value=userdata)
return mock_powerview_userdata_legacy


def _get_mock_powerview_fwversion(fwversion=None, get_resources=None):
mock_powerview_fwversion = MagicMock()
if not fwversion:
fwversion = json.loads(load_fixture("hunterdouglas_powerview/fwversion.json"))
if get_resources:
mock_powerview_fwversion.get_resources = AsyncMock(side_effect=get_resources)
else:
mock_powerview_fwversion.get_resources = AsyncMock(return_value=fwversion)
return mock_powerview_fwversion


async def test_user_form(hass):
Expand Down Expand Up @@ -92,6 +114,53 @@ async def test_user_form(hass):
assert result4["type"] == "abort"


async def test_user_form_legacy(hass):
"""Test we get the user form with a legacy device."""
await setup.async_setup_component(hass, "persistent_notification", {})
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["errors"] == {}

mock_powerview_userdata = _get_mock_powerview_legacy_userdata()
mock_powerview_fwversion = _get_mock_powerview_fwversion()
with patch(
"homeassistant.components.hunterdouglas_powerview.UserData",
return_value=mock_powerview_userdata,
), patch(
"homeassistant.components.hunterdouglas_powerview.ApiEntryPoint",
return_value=mock_powerview_fwversion,
), patch(
"homeassistant.components.hunterdouglas_powerview.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{"host": "1.2.3.4"},
)
await hass.async_block_till_done()

assert result2["type"] == "create_entry"
assert result2["title"] == "PowerView Hub Gen 1"
assert result2["data"] == {
"host": "1.2.3.4",
}
assert len(mock_setup_entry.mock_calls) == 1

result3 = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result3["type"] == "form"
assert result3["errors"] == {}

result4 = await hass.config_entries.flow.async_configure(
result3["flow_id"],
{"host": "1.2.3.4"},
)
assert result4["type"] == "abort"


@pytest.mark.parametrize("source, discovery_info", DISCOVERY_DATA)
async def test_form_homekit_and_dhcp_cannot_connect(hass, source, discovery_info):
"""Test we get the form with homekit and dhcp source."""
Expand Down
10 changes: 10 additions & 0 deletions tests/fixtures/hunterdouglas_powerview/fwversion.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"firmware": {
"mainProcessor": {
"name": "PowerView Hub",
"revision": 1,
"subRevision": 1,
"build": 857
}
}
}