Skip to content

Commit

Permalink
Merge pull request #670 from blockarchitech/garage-door
Browse files Browse the repository at this point in the history
feat: add cover platform for garage door
  • Loading branch information
SecKatie authored Feb 20, 2025
2 parents 9d0de69 + bcc6b1c commit 4bdda99
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 1 deletion.
3 changes: 2 additions & 1 deletion custom_components/wyzeapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"climate",
"alarm_control_panel",
"sensor",
"siren"
"siren",
"cover"
] # Fixme: Re add scene
_LOGGER = logging.getLogger(__name__)

Expand Down
156 changes: 156 additions & 0 deletions custom_components/wyzeapi/cover.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
"""Platform for the cover integration."""

from abc import ABC
from datetime import timedelta
import logging
from typing import Any, Callable, List

from wyzeapy import Wyzeapy, CameraService
from wyzeapy.services.camera_service import Camera
from wyzeapy.exceptions import AccessTokenError, ParameterError, UnknownApiError
from wyzeapy.types import DeviceTypes

import homeassistant.components.cover
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers import device_registry as dr
from homeassistant.exceptions import HomeAssistantError
from homeassistant.components.cover import CoverDeviceClass, CoverEntityFeature


from .const import CAMERA_UPDATED, CONF_CLIENT, DOMAIN, COVER_UPDATED
from .token_manager import token_exception_handler

_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = "Data provided by Wyze"

@token_exception_handler
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry,
async_add_entities: Callable[[List[Any], bool], None]) -> None:
"""
This function sets up the config_entry
:param hass: Home Assistant instance
:param config_entry: The current config_entry
:param async_add_entities: This function adds entities to the config_entry
:return:
"""

_LOGGER.debug("""Creating new WyzeApi cover component""")
client: Wyzeapy = hass.data[DOMAIN][config_entry.entry_id][CONF_CLIENT]
camera_service = await client.camera_service
cameras: List[Camera] = await camera_service.get_cameras()
garages = []
for camera in cameras:
if camera.device_params["dongle_product_model"] == "HL_CGDC":
garages.append(WyzeGarageDoor(camera_service, camera))


async_add_entities(garages, True)


class WyzeGarageDoor(homeassistant.components.cover.CoverEntity, ABC):
"""Representation of a Wyze Garage Door."""
_attr_device_class = CoverDeviceClass.GARAGE
_attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
_attr_has_entity_name = True


def __init__(self, camera_service: CameraService, camera: Camera):
"""Initialize a Wyze garage door."""
self._camera = camera
if self._camera.type not in [
DeviceTypes.CAMERA
]:
raise HomeAssistantError(f"Invalid device type: {self._camera.type}")

self._camera_service = camera_service
self._available = self._camera.available

@property
def device_info(self):
"""Return device information about this entity."""
return {
"identifiers": {(DOMAIN, self._camera.mac)},
"name": f"{self._camera.nickname}",
"connections": {
(
dr.CONNECTION_NETWORK_MAC,
self._camera.mac
)
}
}
@property
def extra_state_attributes(self):
"""Return device attributes of the entity."""
return {
ATTR_ATTRIBUTION: ATTRIBUTION,
"device model": f"{self._camera.product_model}.{self._camera.device_params['dongle_product_model']}"
}

@property
def should_poll(self) -> bool:
return False

@token_exception_handler
async def async_open_cover(self, **kwargs):
"""Open the cover."""
try:
await self._camera_service.garage_door_open(self._camera)
except (AccessTokenError, ParameterError, UnknownApiError) as err:
raise HomeAssistantError(f"Wyze returned an error: {err.args}") from err
except Exception as err:
raise HomeAssistantError(err) from err
else:
self._camera.garage = True
self.async_write_ha_state()

@token_exception_handler
async def async_close_cover(self, **kwargs):
"""Close the cover."""
try:
await self._camera_service.garage_door_close(self._camera)
except (AccessTokenError, ParameterError, UnknownApiError) as err:
raise HomeAssistantError(f"Wyze returned an error: {err.args}") from err
except Exception as err:
raise HomeAssistantError(err) from err
else:
self._camera.garage = False
self.async_write_ha_state()

@property
def is_closed(self):
"""Return if the cover is closed."""
return self._camera.garage == False

@property
def available(self):
"""Return the connection status of this cover."""
return self._camera.available

@property
def unique_id(self):
"""Define a unique id for this entity."""
return f"{self._camera.mac}_GarageDoor"

@property
def name(self):
"""Return the name of the garage door."""
return f"Garage Door"

async def async_added_to_hass(self) -> None:
self.async_on_remove(
async_dispatcher_connect(
self.hass,
f"{CAMERA_UPDATED}-{self._camera.mac}",
self.handle_camera_update,
)
)

@callback
def handle_camera_update(self, camera: Camera) -> None:
"""Update the cover whenever there is an update"""
self._camera = camera
self.async_write_ha_state()

0 comments on commit 4bdda99

Please sign in to comment.