Add abode support for CUE automations (#32296)

* Add support for CUE automations

* Update requirements

* Minor update to string name
This commit is contained in:
Paulus Schoutsen 2020-03-04 14:54:28 -08:00 committed by GitHub
parent 2abdfc9da6
commit d1beb92c5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 66 additions and 102 deletions

View File

@ -2,7 +2,6 @@
from asyncio import gather
from copy import deepcopy
from functools import partial
import logging
from abodepy import Abode
from abodepy.exceptions import AbodeException
@ -24,15 +23,13 @@ from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.entity import Entity
from .const import ATTRIBUTION, DEFAULT_CACHEDB, DOMAIN
_LOGGER = logging.getLogger(__name__)
from .const import ATTRIBUTION, DEFAULT_CACHEDB, DOMAIN, LOGGER
CONF_POLLING = "polling"
SERVICE_SETTINGS = "change_setting"
SERVICE_CAPTURE_IMAGE = "capture_image"
SERVICE_TRIGGER = "trigger_quick_action"
SERVICE_TRIGGER_AUTOMATION = "trigger_automation"
ATTR_DEVICE_ID = "device_id"
ATTR_DEVICE_NAME = "device_name"
@ -47,8 +44,6 @@ ATTR_APP_TYPE = "app_type"
ATTR_EVENT_BY = "event_by"
ATTR_VALUE = "value"
ABODE_DEVICE_ID_LIST_SCHEMA = vol.Schema([str])
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
@ -68,7 +63,7 @@ CHANGE_SETTING_SCHEMA = vol.Schema(
CAPTURE_IMAGE_SCHEMA = vol.Schema({ATTR_ENTITY_ID: cv.entity_ids})
TRIGGER_SCHEMA = vol.Schema({ATTR_ENTITY_ID: cv.entity_ids})
AUTOMATION_SCHEMA = vol.Schema({ATTR_ENTITY_ID: cv.entity_ids})
ABODE_PLATFORMS = [
"alarm_control_panel",
@ -87,7 +82,6 @@ class AbodeSystem:
def __init__(self, abode, polling):
"""Initialize the system."""
self.abode = abode
self.polling = polling
self.entity_ids = set()
@ -124,7 +118,7 @@ async def async_setup_entry(hass, config_entry):
hass.data[DOMAIN] = AbodeSystem(abode, polling)
except (AbodeException, ConnectTimeout, HTTPError) as ex:
_LOGGER.error("Unable to connect to Abode: %s", str(ex))
LOGGER.error("Unable to connect to Abode: %s", str(ex))
return False
for platform in ABODE_PLATFORMS:
@ -143,7 +137,7 @@ async def async_unload_entry(hass, config_entry):
"""Unload a config entry."""
hass.services.async_remove(DOMAIN, SERVICE_SETTINGS)
hass.services.async_remove(DOMAIN, SERVICE_CAPTURE_IMAGE)
hass.services.async_remove(DOMAIN, SERVICE_TRIGGER)
hass.services.async_remove(DOMAIN, SERVICE_TRIGGER_AUTOMATION)
tasks = []
@ -174,7 +168,7 @@ def setup_hass_services(hass):
try:
hass.data[DOMAIN].abode.set_setting(setting, value)
except AbodeException as ex:
_LOGGER.warning(ex)
LOGGER.warning(ex)
def capture_image(call):
"""Capture a new image."""
@ -190,8 +184,8 @@ def setup_hass_services(hass):
signal = f"abode_camera_capture_{entity_id}"
dispatcher_send(hass, signal)
def trigger_quick_action(call):
"""Trigger a quick action."""
def trigger_automation(call):
"""Trigger an Abode automation."""
entity_ids = call.data.get(ATTR_ENTITY_ID, None)
target_entities = [
@ -201,7 +195,7 @@ def setup_hass_services(hass):
]
for entity_id in target_entities:
signal = f"abode_trigger_quick_action_{entity_id}"
signal = f"abode_trigger_automation_{entity_id}"
dispatcher_send(hass, signal)
hass.services.register(
@ -213,7 +207,7 @@ def setup_hass_services(hass):
)
hass.services.register(
DOMAIN, SERVICE_TRIGGER, trigger_quick_action, schema=TRIGGER_SCHEMA
DOMAIN, SERVICE_TRIGGER_AUTOMATION, trigger_automation, schema=AUTOMATION_SCHEMA
)
@ -226,7 +220,7 @@ async def setup_hass_events(hass):
hass.data[DOMAIN].abode.events.stop()
hass.data[DOMAIN].abode.logout()
_LOGGER.info("Logged out of Abode")
LOGGER.info("Logged out of Abode")
if not hass.data[DOMAIN].polling:
await hass.async_add_executor_job(hass.data[DOMAIN].abode.events.start)
@ -384,11 +378,14 @@ class AbodeAutomation(Entity):
"""Return the state attributes."""
return {
ATTR_ATTRIBUTION: ATTRIBUTION,
"automation_id": self._automation.automation_id,
"type": self._automation.type,
"sub_type": self._automation.sub_type,
"type": "CUE automation",
}
@property
def unique_id(self):
"""Return a unique ID to use for this automation."""
return self._automation.automation_id
def _update_callback(self, device):
"""Update the automation state."""
self._automation.refresh()

View File

@ -1,6 +1,4 @@
"""Support for Abode Security System alarm control panels."""
import logging
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_AWAY,
@ -16,8 +14,6 @@ from homeassistant.const import (
from . import AbodeDevice
from .const import ATTRIBUTION, DOMAIN
_LOGGER = logging.getLogger(__name__)
ICON = "mdi:security"
@ -50,6 +46,11 @@ class AbodeAlarm(AbodeDevice, alarm.AlarmControlPanel):
state = None
return state
@property
def code_arm_required(self):
"""Whether the code is required for arm actions."""
return False
@property
def supported_features(self) -> int:
"""Return the list of supported features."""

View File

@ -1,17 +1,11 @@
"""Support for Abode Security System binary sensors."""
import logging
import abodepy.helpers.constants as CONST
import abodepy.helpers.timeline as TIMELINE
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from . import AbodeAutomation, AbodeDevice
from . import AbodeDevice
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Abode binary sensor devices."""
@ -30,13 +24,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
for device in data.abode.get_devices(generic_type=device_types):
entities.append(AbodeBinarySensor(data, device))
for automation in data.abode.get_automations(generic_type=CONST.TYPE_QUICK_ACTION):
entities.append(
AbodeQuickActionBinarySensor(
data, automation, TIMELINE.AUTOMATION_EDIT_GROUP
)
)
async_add_entities(entities)
@ -52,22 +39,3 @@ class AbodeBinarySensor(AbodeDevice, BinarySensorDevice):
def device_class(self):
"""Return the class of the binary sensor."""
return self._device.generic_type
class AbodeQuickActionBinarySensor(AbodeAutomation, BinarySensorDevice):
"""A binary sensor implementation for Abode quick action automations."""
async def async_added_to_hass(self):
"""Subscribe Abode events."""
await super().async_added_to_hass()
signal = f"abode_trigger_quick_action_{self.entity_id}"
async_dispatcher_connect(self.hass, signal, self.trigger)
def trigger(self):
"""Trigger a quick automation."""
self._automation.trigger()
@property
def is_on(self):
"""Return True if the binary sensor is on."""
return self._automation.is_active

View File

@ -1,6 +1,5 @@
"""Support for Abode Security System cameras."""
from datetime import timedelta
import logging
import abodepy.helpers.constants as CONST
import abodepy.helpers.timeline as TIMELINE
@ -11,12 +10,10 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.util import Throttle
from . import AbodeDevice
from .const import DOMAIN
from .const import DOMAIN, LOGGER
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90)
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Abode camera devices."""
@ -71,7 +68,7 @@ class AbodeCamera(AbodeDevice, Camera):
self._response.raise_for_status()
except requests.HTTPError as err:
_LOGGER.warning("Failed to get camera image: %s", err)
LOGGER.warning("Failed to get camera image: %s", err)
self._response = None
else:
self._response = None

View File

@ -1,6 +1,4 @@
"""Config flow for the Abode Security System component."""
import logging
from abodepy import Abode
from abodepy.exceptions import AbodeException
from requests.exceptions import ConnectTimeout, HTTPError
@ -10,12 +8,10 @@ from homeassistant import config_entries
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import callback
from .const import DEFAULT_CACHEDB, DOMAIN # pylint: disable=unused-import
from .const import DEFAULT_CACHEDB, DOMAIN, LOGGER # pylint: disable=unused-import
CONF_POLLING = "polling"
_LOGGER = logging.getLogger(__name__)
class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Config flow for Abode."""
@ -32,7 +28,6 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
@ -50,7 +45,7 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
)
except (AbodeException, ConnectTimeout, HTTPError) as ex:
_LOGGER.error("Unable to connect to Abode: %s", str(ex))
LOGGER.error("Unable to connect to Abode: %s", str(ex))
if ex.errcode == 400:
return self._show_form({"base": "invalid_credentials"})
return self._show_form({"base": "connection_error"})
@ -76,7 +71,7 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_import(self, import_config):
"""Import a config entry from configuration.yaml."""
if self._async_current_entries():
_LOGGER.warning("Only one configuration of abode is allowed.")
LOGGER.warning("Only one configuration of abode is allowed.")
return self.async_abort(reason="single_instance_allowed")
return await self.async_step_user(import_config)

View File

@ -1,4 +1,8 @@
"""Constants for the Abode Security System component."""
import logging
LOGGER = logging.getLogger(__package__)
DOMAIN = "abode"
ATTRIBUTION = "Data provided by goabode.com"

View File

@ -1,6 +1,4 @@
"""Support for Abode Security System covers."""
import logging
import abodepy.helpers.constants as CONST
from homeassistant.components.cover import CoverDevice
@ -8,8 +6,6 @@ from homeassistant.components.cover import CoverDevice
from . import AbodeDevice
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Abode cover devices."""

View File

@ -1,5 +1,4 @@
"""Support for Abode Security System lights."""
import logging
from math import ceil
import abodepy.helpers.constants as CONST
@ -21,8 +20,6 @@ from homeassistant.util.color import (
from . import AbodeDevice
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Abode light devices."""

View File

@ -1,6 +1,4 @@
"""Support for the Abode Security System locks."""
import logging
import abodepy.helpers.constants as CONST
from homeassistant.components.lock import LockDevice
@ -8,8 +6,6 @@ from homeassistant.components.lock import LockDevice
from . import AbodeDevice
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Abode lock devices."""

View File

@ -3,7 +3,7 @@
"name": "Abode",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/abode",
"requirements": ["abodepy==0.17.0"],
"requirements": ["abodepy==0.18.1"],
"dependencies": [],
"codeowners": ["@shred86"]
}

View File

@ -1,6 +1,4 @@
"""Support for Abode Security System sensors."""
import logging
import abodepy.helpers.constants as CONST
from homeassistant.const import (
@ -12,8 +10,6 @@ from homeassistant.const import (
from . import AbodeDevice
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
# Sensor types: Name, icon
SENSOR_TYPES = {
CONST.TEMP_STATUS_KEY: ["Temperature", DEVICE_CLASS_TEMPERATURE],

View File

@ -7,7 +7,7 @@ change_setting:
fields:
setting: {description: Setting to change., example: beeper_mute}
value: {description: Value of the setting., example: '1'}
trigger_quick_action:
description: Trigger an Abode quick action.
trigger_automation:
description: Trigger an Abode automation.
fields:
entity_id: {description: Entity id of the quick action to trigger., example: binary_sensor.home_quick_action}
entity_id: {description: Entity id of the automation to trigger., example: switch.my_automation}

View File

@ -1,18 +1,17 @@
"""Support for Abode Security System switches."""
import logging
import abodepy.helpers.constants as CONST
import abodepy.helpers.timeline as TIMELINE
from homeassistant.components.switch import SwitchDevice
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from . import AbodeAutomation, AbodeDevice
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
DEVICE_TYPES = [CONST.TYPE_SWITCH, CONST.TYPE_VALVE]
ICON = "mdi:robot"
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Abode switch devices."""
@ -24,7 +23,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
for device in data.abode.get_devices(generic_type=device_type):
entities.append(AbodeSwitch(data, device))
for automation in data.abode.get_automations(generic_type=CONST.TYPE_AUTOMATION):
for automation in data.abode.get_automations():
entities.append(
AbodeAutomationSwitch(data, automation, TIMELINE.AUTOMATION_EDIT_GROUP)
)
@ -52,15 +51,33 @@ class AbodeSwitch(AbodeDevice, SwitchDevice):
class AbodeAutomationSwitch(AbodeAutomation, SwitchDevice):
"""A switch implementation for Abode automations."""
async def async_added_to_hass(self):
"""Subscribe Abode events."""
await super().async_added_to_hass()
signal = f"abode_trigger_automation_{self.entity_id}"
async_dispatcher_connect(self.hass, signal, self.trigger)
def turn_on(self, **kwargs):
"""Turn on the device."""
self._automation.set_active(True)
"""Enable the automation."""
if self._automation.enable(True):
self.schedule_update_ha_state()
def turn_off(self, **kwargs):
"""Turn off the device."""
self._automation.set_active(False)
"""Disable the automation."""
if self._automation.enable(False):
self.schedule_update_ha_state()
def trigger(self):
"""Trigger the automation."""
self._automation.trigger()
@property
def is_on(self):
"""Return True if the binary sensor is on."""
return self._automation.is_active
"""Return True if the automation is enabled."""
return self._automation.is_enabled
@property
def icon(self):
"""Return the robot icon to match Home Assistant automations."""
return ICON

View File

@ -106,7 +106,7 @@ WazeRouteCalculator==0.12
YesssSMS==0.4.1
# homeassistant.components.abode
abodepy==0.17.0
abodepy==0.18.1
# homeassistant.components.mcp23017
adafruit-blinka==3.9.0

View File

@ -26,7 +26,7 @@ RtmAPI==0.7.2
YesssSMS==0.4.1
# homeassistant.components.abode
abodepy==0.17.0
abodepy==0.18.1
# homeassistant.components.androidtv
adb-shell==0.1.1