Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
44 changes: 43 additions & 1 deletion homeassistant/components/homematicip_cloud/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging

from homematicip.aio.group import AsyncHeatingGroup
from homematicip.base.helpers import handle_config
import voluptuous as vol

from homeassistant import config_entries
Expand All @@ -26,17 +27,23 @@

_LOGGER = logging.getLogger(__name__)

ATTR_ACCESSPOINT_ID = "accesspoint_id"
ATTR_ANONYMIZE = "anonymize"
ATTR_CLIMATE_PROFILE_INDEX = "climate_profile_index"
ATTR_CONFIG_OUTPUT_FILE_PREFIX = "config_output_file_prefix"
ATTR_CONFIG_OUTPUT_PATH = "config_output_path"
ATTR_DURATION = "duration"
ATTR_ENDTIME = "endtime"
ATTR_TEMPERATURE = "temperature"
ATTR_ACCESSPOINT_ID = "accesspoint_id"

DEFAULT_CONFIG_FILE_PREFIX = "hmip-config"

SERVICE_ACTIVATE_ECO_MODE_WITH_DURATION = "activate_eco_mode_with_duration"
SERVICE_ACTIVATE_ECO_MODE_WITH_PERIOD = "activate_eco_mode_with_period"
SERVICE_ACTIVATE_VACATION = "activate_vacation"
SERVICE_DEACTIVATE_ECO_MODE = "deactivate_eco_mode"
SERVICE_DEACTIVATE_VACATION = "deactivate_vacation"
SERVICE_DUMP_HAP_CONFIG = "dump_hap_config"
SERVICE_SET_ACTIVE_CLIMATE_PROFILE = "set_active_climate_profile"

CONFIG_SCHEMA = vol.Schema(
Expand Down Expand Up @@ -96,6 +103,14 @@
}
)

SCHEMA_DUMP_HAP_CONFIG = vol.Schema(
{
vol.Required(ATTR_CONFIG_OUTPUT_PATH, default=""): cv.string,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should make this optional without default. Use dict.get to return None as default in the service handler.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

vol.Required(ATTR_CONFIG_OUTPUT_FILE_PREFIX, default=""): cv.string,
vol.Required(ATTR_ANONYMIZE, default=True): cv.boolean,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Items with default should be optional.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
)


async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
"""Set up the HomematicIP Cloud component."""
Expand Down Expand Up @@ -239,6 +254,33 @@ async def _set_active_climate_profile(service):
schema=SCHEMA_SET_ACTIVE_CLIMATE_PROFILE,
)

async def _async_dump_hap_config(service):
"""Service to dump the configuration of a Homematic IP Access Point."""
config_path = service.data[ATTR_CONFIG_OUTPUT_PATH] or hass.config.config_dir
config_file_prefix = (
service.data[ATTR_CONFIG_OUTPUT_FILE_PREFIX] or DEFAULT_CONFIG_FILE_PREFIX

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the default to the service schema.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

)
anonymize = service.data[ATTR_ANONYMIZE]

for hap in hass.data[DOMAIN].values():
hap_sgtin = hap.config_entry.title

if anonymize:
hap_sgtin = hap_sgtin[-4:]

config_file = f"{config_path}/{config_file_prefix}_{hap_sgtin}.json"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use pathlib.Path to construct the path. Use f-strings to create the filename.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


json_state = await hap.home.download_configuration()
json_state = handle_config(json_state, anonymize)
open(config_file, mode="w", encoding="utf8").write(json_state)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


hass.services.async_register(
DOMAIN,
SERVICE_DUMP_HAP_CONFIG,
_async_dump_hap_config,
schema=SCHEMA_DUMP_HAP_CONFIG,
)

def _get_home(hapid: str):
"""Return a HmIP home."""
hap = hass.data[DOMAIN].get(hapid)
Expand Down
13 changes: 12 additions & 1 deletion homeassistant/components/homematicip_cloud/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,15 @@ set_active_climate_profile:
description: The index of the climate profile (1 based)
example: 1


dump_hap_config:
description: Dump the configuration of the Homematic IP Access Point(s).
fields:
config_output_path:
description: (Default is 'Your home-assistant config directory') Path where to store the config.
example: '/config'
config_output_file_prefix:
description: (Default is 'hmip-config') Name of the config file. The SGTIN of the AP will always be appended.
example: 'hmip-config'
anonymize:
description: (Default is True) Should the Configuration be anonymized?
example: True
17 changes: 16 additions & 1 deletion tests/components/homematicip_cloud/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from homeassistant.components import homematicip_cloud as hmipc
from homeassistant.setup import async_setup_component

from tests.common import MockConfigEntry, mock_coro
from tests.common import Mock, MockConfigEntry, mock_coro


async def test_config_with_accesspoint_passed_to_config_entry(hass):
Expand Down Expand Up @@ -150,3 +150,18 @@ async def test_unload_entry(hass):
assert await hmipc.async_unload_entry(hass, entry)
assert len(mock_hap.return_value.async_reset.mock_calls) == 1
assert hass.data[hmipc.DOMAIN] == {}


async def test_hmip_dump_hap_config_services(hass, mock_hap_with_service):
"""Test dump configuration services."""

with patch(
"homeassistant.components.homematicip_cloud.open", return_value=Mock()
) as open_mock:
await hass.services.async_call(
"homematicip_cloud", "dump_hap_config", {"anonymize": True}, blocking=True
)
home = mock_hap_with_service.home
assert home.mock_calls[-1][0] == "download_configuration"
assert len(home.mock_calls) == 8 # pylint: disable=W0212
assert len(open_mock.mock_calls) == 1