diff --git a/.coveragerc b/.coveragerc index e2eda11cb1e..811528b2911 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1110,6 +1110,7 @@ omit = homeassistant/components/simplisafe/__init__.py homeassistant/components/simplisafe/alarm_control_panel.py homeassistant/components/simplisafe/binary_sensor.py + homeassistant/components/simplisafe/button.py homeassistant/components/simplisafe/lock.py homeassistant/components/simplisafe/sensor.py homeassistant/components/simulated/sensor.py diff --git a/homeassistant/components/simplisafe/__init__.py b/homeassistant/components/simplisafe/__init__.py index c28a3740694..53aa9e84054 100644 --- a/homeassistant/components/simplisafe/__init__.py +++ b/homeassistant/components/simplisafe/__init__.py @@ -71,6 +71,7 @@ from homeassistant.helpers.dispatcher import ( async_dispatcher_send, ) from homeassistant.helpers.entity import DeviceInfo +from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.service import ( async_register_admin_service, verify_domain_control, @@ -126,6 +127,7 @@ EVENT_SIMPLISAFE_NOTIFICATION = "SIMPLISAFE_NOTIFICATION" PLATFORMS = [ Platform.ALARM_CONTROL_PANEL, Platform.BINARY_SENSOR, + Platform.BUTTON, Platform.LOCK, Platform.SENSOR, ] @@ -257,6 +259,45 @@ def _async_get_system_for_service_call( raise ValueError(f"No system for device ID: {device_id}") +@callback +def _async_log_deprecated_service_call( + hass: HomeAssistant, + call: ServiceCall, + alternate_service: str, + alternate_target: str, + breaks_in_ha_version: str, +) -> None: + """Log a warning about a deprecated service call.""" + deprecated_service = f"{call.domain}.{call.service}" + + async_create_issue( + hass, + DOMAIN, + f"deprecated_service_{deprecated_service}", + breaks_in_ha_version=breaks_in_ha_version, + is_fixable=True, + is_persistent=True, + severity=IssueSeverity.WARNING, + translation_key="deprecated_service", + translation_placeholders={ + "alternate_service": alternate_service, + "alternate_target": alternate_target, + "deprecated_service": deprecated_service, + }, + ) + + LOGGER.warning( + ( + 'The "%s" service is deprecated and will be removed in %s; use the "%s" ' + 'service and pass it a target entity ID of "%s"' + ), + deprecated_service, + breaks_in_ha_version, + alternate_service, + alternate_target, + ) + + @callback def _async_register_base_station( hass: HomeAssistant, entry: ConfigEntry, system: SystemType @@ -347,6 +388,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: @extract_system async def async_clear_notifications(call: ServiceCall, system: SystemType) -> None: """Clear all active notifications.""" + _async_log_deprecated_service_call( + hass, + call, + "button.press", + "button.alarm_control_panel_clear_notifications", + "2022.12.0", + ) await system.async_clear_notifications() @_verify_domain_control @@ -839,9 +887,7 @@ class SimpliSafeEntity(CoordinatorEntity): @callback def async_update_from_rest_api(self) -> None: """Update the entity when new data comes from the REST API.""" - raise NotImplementedError() @callback def async_update_from_websocket_event(self, event: WebsocketEvent) -> None: """Update the entity when new data comes from the websocket.""" - raise NotImplementedError() diff --git a/homeassistant/components/simplisafe/button.py b/homeassistant/components/simplisafe/button.py new file mode 100644 index 00000000000..a10d958a94a --- /dev/null +++ b/homeassistant/components/simplisafe/button.py @@ -0,0 +1,93 @@ +"""Buttons for the SimpliSafe integration.""" +from __future__ import annotations + +from collections.abc import Awaitable, Callable +from dataclasses import dataclass + +from simplipy.errors import SimplipyError +from simplipy.system import System + +from homeassistant.components.button import ButtonEntity, ButtonEntityDescription +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.entity import EntityCategory +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from . import SimpliSafe, SimpliSafeEntity +from .const import DOMAIN +from .typing import SystemType + + +@dataclass +class SimpliSafeButtonDescriptionMixin: + """Define an entity description mixin for SimpliSafe buttons.""" + + push_action: Callable[[System], Awaitable] + + +@dataclass +class SimpliSafeButtonDescription( + ButtonEntityDescription, SimpliSafeButtonDescriptionMixin +): + """Describe a SimpliSafe button entity.""" + + +BUTTON_KIND_CLEAR_NOTIFICATIONS = "clear_notifications" + + +async def _async_clear_notifications(system: System) -> None: + """Reboot the SimpliSafe.""" + await system.async_clear_notifications() + + +BUTTON_DESCRIPTIONS = ( + SimpliSafeButtonDescription( + key=BUTTON_KIND_CLEAR_NOTIFICATIONS, + name="Clear notifications", + push_action=_async_clear_notifications, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up SimpliSafe buttons based on a config entry.""" + simplisafe = hass.data[DOMAIN][entry.entry_id] + + async_add_entities( + [ + SimpliSafeButton(simplisafe, system, description) + for system in simplisafe.systems.values() + for description in BUTTON_DESCRIPTIONS + ] + ) + + +class SimpliSafeButton(SimpliSafeEntity, ButtonEntity): + """Define a SimpliSafe button.""" + + _attr_entity_category = EntityCategory.CONFIG + + entity_description: SimpliSafeButtonDescription + + def __init__( + self, + simplisafe: SimpliSafe, + system: SystemType, + description: SimpliSafeButtonDescription, + ) -> None: + """Initialize the SimpliSafe alarm.""" + super().__init__(simplisafe, system) + + self.entity_description = description + + async def async_press(self) -> None: + """Send out a restart command.""" + try: + await self.entity_description.push_action(self._system) + except SimplipyError as err: + raise HomeAssistantError( + f'Error while pressing button "{self.entity_id}": {err}' + ) from err diff --git a/homeassistant/components/simplisafe/services.yaml b/homeassistant/components/simplisafe/services.yaml index 9875d5baa37..6f9cedc77cb 100644 --- a/homeassistant/components/simplisafe/services.yaml +++ b/homeassistant/components/simplisafe/services.yaml @@ -1,16 +1,4 @@ # Describes the format for available SimpliSafe services -clear_notifications: - name: Clear notifications - description: Clear any active SimpliSafe notifications - fields: - device_id: - name: System - description: The system to remove the PIN from - required: true - selector: - device: - integration: simplisafe - model: alarm_control_panel remove_pin: name: Remove PIN description: Remove a PIN by its label or value. diff --git a/homeassistant/components/simplisafe/strings.json b/homeassistant/components/simplisafe/strings.json index 618c21566f7..bc03ab4c514 100644 --- a/homeassistant/components/simplisafe/strings.json +++ b/homeassistant/components/simplisafe/strings.json @@ -29,5 +29,11 @@ } } } + }, + "issues": { + "deprecated_service": { + "title": "The {deprecated_service} service is being removed", + "description": "Update any automations or scripts that use this service to instead use the `{alternate_service}` service with a target entity ID of `{alternate_target}`. Then, click SUBMIT below to mark this issue as resolved." + } } } diff --git a/homeassistant/components/simplisafe/translations/en.json b/homeassistant/components/simplisafe/translations/en.json index baa167ca951..724e3b5af28 100644 --- a/homeassistant/components/simplisafe/translations/en.json +++ b/homeassistant/components/simplisafe/translations/en.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "This SimpliSafe account is already in use.", - "email_2fa_timed_out": "Timed out while waiting for email-based two-factor authentication.", "reauth_successful": "Re-authentication was successful", "wrong_account": "The user credentials provided do not match this SimpliSafe account." }, @@ -12,33 +11,21 @@ "invalid_auth_code_length": "SimpliSafe authorization codes are 45 characters in length", "unknown": "Unexpected error" }, - "progress": { - "email_2fa": "Check your email for a verification link from Simplisafe." - }, "step": { - "reauth_confirm": { - "data": { - "password": "Password" - }, - "description": "Please re-enter the password for {username}.", - "title": "Reauthenticate Integration" - }, - "sms_2fa": { - "data": { - "code": "Code" - }, - "description": "Input the two-factor authentication code sent to you via SMS." - }, "user": { "data": { - "auth_code": "Authorization Code", - "password": "Password", - "username": "Username" + "auth_code": "Authorization Code" }, "description": "SimpliSafe authenticates users via its web app. Due to technical limitations, there is a manual step at the end of this process; please ensure that you read the [documentation](http://home-assistant.io/integrations/simplisafe#getting-an-authorization-code) before starting.\n\nWhen you are ready, click [here]({url}) to open the SimpliSafe web app and input your credentials. If you've already logged into SimpliSafe in your browser, you may want to open a new tab, then copy/paste the above URL into that tab.\n\nWhen the process is complete, return here and input the authorization code from the `com.simplisafe.mobile` URL." } } }, + "issues": { + "deprecated_service": { + "description": "Update any automations or scripts that use this service to instead use the `{alternate_service}` service with a target entity ID of `{alternate_target}`. Then, click SUBMIT below to mark this issue as resolved.", + "title": "The {deprecated_service} service is being removed" + } + }, "options": { "step": { "init": {