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
50 changes: 49 additions & 1 deletion homeassistant/components/homematicip_cloud/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""Support for HomematicIP Cloud devices."""
import logging
from pathlib import Path

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 +28,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 +104,16 @@
}
)

SCHEMA_DUMP_HAP_CONFIG = vol.Schema(
{
vol.Optional(ATTR_CONFIG_OUTPUT_PATH): cv.string,
vol.Optional(
ATTR_CONFIG_OUTPUT_FILE_PREFIX, default=DEFAULT_CONFIG_FILE_PREFIX
): cv.string,
vol.Optional(ATTR_ANONYMIZE, default=True): cv.boolean,
}
)


async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
"""Set up the HomematicIP Cloud component."""
Expand Down Expand Up @@ -239,6 +257,36 @@ 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.get(ATTR_CONFIG_OUTPUT_PATH) or hass.config.config_dir
)
config_file_prefix = service.data[ATTR_CONFIG_OUTPUT_FILE_PREFIX]
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:]

file_name = f"{config_file_prefix}_{hap_sgtin}.json"
path = Path(config_path)
config_file = path / file_name

json_state = await hap.home.download_configuration()
json_state = handle_config(json_state, anonymize)

config_file.write_text(json_state, encoding="utf8")

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
15 changes: 14 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,16 @@ 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("pathlib.Path.write_text", return_value=Mock()) as write_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(write_mock.mock_calls) > 0