From 918940a0c681a453a4da46b8afbc5d6300eb1e4f Mon Sep 17 00:00:00 2001
From: hahn-th <post@thomas-hahn.org>
Date: Thu, 3 Nov 2022 12:03:49 +0100
Subject: [PATCH] Add HmIP-WGC to homematicip_cloud integration (#75733)

* Add HmIP-WGC

* remove unused code

* removed test test_manually_configured_platform
---
 .../components/homematicip_cloud/button.py    |  41 +++++++
 .../components/homematicip_cloud/const.py     |   1 +
 .../homematicip_cloud/test_button.py          |  39 +++++++
 .../homematicip_cloud/test_device.py          |   2 +-
 tests/fixtures/homematicip_cloud.json         | 105 ++++++++++++++++++
 5 files changed, 187 insertions(+), 1 deletion(-)
 create mode 100644 homeassistant/components/homematicip_cloud/button.py
 create mode 100644 tests/components/homematicip_cloud/test_button.py

diff --git a/homeassistant/components/homematicip_cloud/button.py b/homeassistant/components/homematicip_cloud/button.py
new file mode 100644
index 00000000000..3fb8ebe20bd
--- /dev/null
+++ b/homeassistant/components/homematicip_cloud/button.py
@@ -0,0 +1,41 @@
+"""Support for HomematicIP Cloud button devices."""
+from __future__ import annotations
+
+from homematicip.aio.device import AsyncWallMountedGarageDoorController
+
+from homeassistant.components.button import ButtonEntity
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity_platform import AddEntitiesCallback
+
+from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericEntity
+from .hap import HomematicipHAP
+
+
+async def async_setup_entry(
+    hass: HomeAssistant,
+    config_entry: ConfigEntry,
+    async_add_entities: AddEntitiesCallback,
+) -> None:
+    """Set up the HomematicIP button from a config entry."""
+    hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
+    entities: list[HomematicipGenericEntity] = []
+    for device in hap.home.devices:
+        if isinstance(device, AsyncWallMountedGarageDoorController):
+            entities.append(HomematicipGarageDoorControllerButton(hap, device))
+
+    if entities:
+        async_add_entities(entities)
+
+
+class HomematicipGarageDoorControllerButton(HomematicipGenericEntity, ButtonEntity):
+    """Representation of the HomematicIP Wall mounted Garage Door Controller."""
+
+    def __init__(self, hap: HomematicipHAP, device) -> None:
+        """Initialize a wall mounted garage door controller."""
+        super().__init__(hap, device)
+        self._attr_icon = "mdi:arrow-up-down"
+
+    async def async_press(self) -> None:
+        """Handle the button press."""
+        await self._device.send_start_impulse()
diff --git a/homeassistant/components/homematicip_cloud/const.py b/homeassistant/components/homematicip_cloud/const.py
index a0f1c84015f..055db90a68c 100644
--- a/homeassistant/components/homematicip_cloud/const.py
+++ b/homeassistant/components/homematicip_cloud/const.py
@@ -10,6 +10,7 @@ DOMAIN = "homematicip_cloud"
 PLATFORMS = [
     Platform.ALARM_CONTROL_PANEL,
     Platform.BINARY_SENSOR,
+    Platform.BUTTON,
     Platform.CLIMATE,
     Platform.COVER,
     Platform.LIGHT,
diff --git a/tests/components/homematicip_cloud/test_button.py b/tests/components/homematicip_cloud/test_button.py
new file mode 100644
index 00000000000..c399bc99327
--- /dev/null
+++ b/tests/components/homematicip_cloud/test_button.py
@@ -0,0 +1,39 @@
+"""Tests for HomematicIP Cloud button."""
+
+from unittest.mock import patch
+
+from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
+from homeassistant.components.button.const import SERVICE_PRESS
+from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN
+from homeassistant.util import dt as dt_util
+
+from .helper import get_and_check_entity_basics
+
+
+async def test_hmip_garage_door_controller_button(hass, default_mock_hap_factory):
+    """Test HomematicipGarageDoorControllerButton."""
+    entity_id = "button.garagentor"
+    entity_name = "Garagentor"
+    device_model = "HmIP-WGC"
+    mock_hap = await default_mock_hap_factory.async_get_mock_hap(
+        test_devices=[entity_name]
+    )
+
+    get_and_check_entity_basics(hass, mock_hap, entity_id, entity_name, device_model)
+
+    state = hass.states.get(entity_id)
+    assert state
+    assert state.state == STATE_UNKNOWN
+
+    now = dt_util.parse_datetime("2021-01-09 12:00:00+00:00")
+    with patch("homeassistant.util.dt.utcnow", return_value=now):
+        await hass.services.async_call(
+            BUTTON_DOMAIN,
+            SERVICE_PRESS,
+            {ATTR_ENTITY_ID: entity_id},
+            blocking=True,
+        )
+
+    state = hass.states.get(entity_id)
+    assert state
+    assert state.state == now.isoformat()
diff --git a/tests/components/homematicip_cloud/test_device.py b/tests/components/homematicip_cloud/test_device.py
index 44b91c4ed47..52b92fdff9a 100644
--- a/tests/components/homematicip_cloud/test_device.py
+++ b/tests/components/homematicip_cloud/test_device.py
@@ -22,7 +22,7 @@ async def test_hmip_load_all_supported_devices(hass, default_mock_hap_factory):
         test_devices=None, test_groups=None
     )
 
-    assert len(mock_hap.hmip_device_by_entity_id) == 262
+    assert len(mock_hap.hmip_device_by_entity_id) == 264
 
 
 async def test_hmip_remove_device(hass, default_mock_hap_factory):
diff --git a/tests/fixtures/homematicip_cloud.json b/tests/fixtures/homematicip_cloud.json
index b0037aa3800..5a7b0516763 100644
--- a/tests/fixtures/homematicip_cloud.json
+++ b/tests/fixtures/homematicip_cloud.json
@@ -6725,6 +6725,111 @@
       "serializedGlobalTradeItemNumber": "3014F7110000000000STE2015",
       "type": "TEMPERATURE_SENSOR_2_EXTERNAL_DELTA",
       "updateState": "TRANSFERING_UPDATE"
+    },
+    "3014F7110000000000000WGC": {
+      "availableFirmwareVersion": "1.0.2",
+      "connectionType": "HMIP_RF",
+      "firmwareVersion": "1.0.2",
+      "firmwareVersionInteger": 65538,
+      "functionalChannels": {
+        "0": {
+          "busConfigMismatch": null,
+          "coProFaulty": false,
+          "coProRestartNeeded": false,
+          "coProUpdateFailure": false,
+          "configPending": false,
+          "deviceId": "3014F7110000000000000WGC",
+          "deviceOverheated": false,
+          "deviceOverloaded": false,
+          "devicePowerFailureDetected": false,
+          "deviceUndervoltage": false,
+          "displayContrast": null,
+          "dutyCycle": false,
+          "functionalChannelType": "DEVICE_BASE",
+          "groupIndex": 0,
+          "groups": ["00000000-0000-0000-0000-000000000011"],
+          "index": 0,
+          "label": "",
+          "lowBat": false,
+          "mountingOrientation": null,
+          "multicastRoutingEnabled": false,
+          "particulateMatterSensorCommunicationError": null,
+          "particulateMatterSensorError": null,
+          "powerShortCircuit": null,
+          "profilePeriodLimitReached": null,
+          "routerModuleEnabled": false,
+          "routerModuleSupported": false,
+          "rssiDeviceValue": -83,
+          "rssiPeerValue": -77,
+          "shortCircuitDataLine": null,
+          "supportedOptionalFeatures": {
+            "IFeatureBusConfigMismatch": false,
+            "IFeatureDeviceCoProError": false,
+            "IFeatureDeviceCoProRestart": false,
+            "IFeatureDeviceCoProUpdate": false,
+            "IFeatureDeviceIdentify": false,
+            "IFeatureDeviceOverheated": false,
+            "IFeatureDeviceOverloaded": false,
+            "IFeatureDeviceParticulateMatterSensorCommunicationError": false,
+            "IFeatureDeviceParticulateMatterSensorError": false,
+            "IFeatureDevicePowerFailure": false,
+            "IFeatureDeviceTemperatureHumiditySensorCommunicationError": false,
+            "IFeatureDeviceTemperatureHumiditySensorError": false,
+            "IFeatureDeviceTemperatureOutOfRange": false,
+            "IFeatureDeviceUndervoltage": true,
+            "IFeatureMulticastRouter": false,
+            "IFeaturePowerShortCircuit": false,
+            "IFeatureProfilePeriodLimit": false,
+            "IFeatureRssiValue": true,
+            "IFeatureShortCircuitDataLine": false,
+            "IOptionalFeatureDisplayContrast": false,
+            "IOptionalFeatureDutyCycle": true,
+            "IOptionalFeatureLowBat": true,
+            "IOptionalFeatureMountingOrientation": false
+          },
+          "temperatureHumiditySensorCommunicationError": null,
+          "temperatureHumiditySensorError": null,
+          "temperatureOutOfRange": false,
+          "unreach": false
+        },
+        "1": {
+          "deviceId": "3014F7110000000000000WGC",
+          "functionalChannelType": "SINGLE_KEY_CHANNEL",
+          "groupIndex": 1,
+          "groups": [
+            "00000000-0000-0000-0000-000000000012",
+            "00000000-0000-0000-0000-000000000013"
+          ],
+          "index": 1,
+          "label": ""
+        },
+        "2": {
+          "deviceId": "3014F7110000000000000WGC",
+          "functionalChannelType": "IMPULSE_OUTPUT_CHANNEL",
+          "groupIndex": 2,
+          "groups": [
+            "00000000-0000-0000-0000-000000000012",
+            "00000000-0000-0000-0000-000000000013"
+          ],
+          "impulseDuration": 0.4,
+          "index": 2,
+          "label": "Taste",
+          "processing": false
+        }
+      },
+      "homeId": "00000000-0000-0000-0000-000000000001",
+      "id": "3014F7110000000000000WGC",
+      "label": "Garagentor",
+      "lastStatusUpdate": 1630920800279,
+      "liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED",
+      "manufacturerCode": 1,
+      "modelId": 331,
+      "modelType": "HmIP-WGC",
+      "oem": "eQ-3",
+      "permanentlyReachable": true,
+      "serializedGlobalTradeItemNumber": "3014F7110000000000000WGC",
+      "type": "WALL_MOUNTED_GARAGE_DOOR_CONTROLLER",
+      "updateState": "UP_TO_DATE"
     }
   },
   "groups": {
-- 
GitLab