Add binary sensor for smarttub errors (#49364)

This commit is contained in:
Matt Zimmerman 2021-05-26 09:25:47 -07:00 committed by GitHub
parent 64661ee2b7
commit ffb9ab21c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 111 additions and 4 deletions

View File

@ -1,7 +1,7 @@
"""Platform for binary sensor integration."""
import logging
from smarttub import SpaReminder
from smarttub import SpaError, SpaReminder
import voluptuous as vol
from homeassistant.components.binary_sensor import (
@ -11,7 +11,7 @@ from homeassistant.components.binary_sensor import (
)
from homeassistant.helpers import entity_platform
from .const import ATTR_REMINDERS, DOMAIN, SMARTTUB_CONTROLLER
from .const import ATTR_ERRORS, ATTR_REMINDERS, DOMAIN, SMARTTUB_CONTROLLER
from .entity import SmartTubEntity, SmartTubSensorBase
_LOGGER = logging.getLogger(__name__)
@ -19,6 +19,13 @@ _LOGGER = logging.getLogger(__name__)
# whether the reminder has been snoozed (bool)
ATTR_REMINDER_SNOOZED = "snoozed"
ATTR_ERROR_CODE = "error_code"
ATTR_ERROR_TITLE = "error_title"
ATTR_ERROR_DESCRIPTION = "error_description"
ATTR_ERROR_TYPE = "error_type"
ATTR_CREATED_AT = "created_at"
ATTR_UPDATED_AT = "updated_at"
# how many days to snooze the reminder for
ATTR_SNOOZE_DAYS = "days"
SNOOZE_REMINDER_SCHEMA = {
@ -34,6 +41,7 @@ async def async_setup_entry(hass, entry, async_add_entities):
entities = []
for spa in controller.spas:
entities.append(SmartTubOnline(controller.coordinator, spa))
entities.append(SmartTubError(controller.coordinator, spa))
entities.extend(
SmartTubReminder(controller.coordinator, spa, reminder)
for reminder in controller.coordinator.data[spa.id][ATTR_REMINDERS].values()
@ -119,3 +127,54 @@ class SmartTubReminder(SmartTubEntity, BinarySensorEntity):
"""Snooze this reminder for the specified number of days."""
await self.reminder.snooze(days)
await self.coordinator.async_request_refresh()
class SmartTubError(SmartTubEntity, BinarySensorEntity):
"""Indicates whether an error code is present.
There may be 0 or more errors. If there are >0, we show the first one.
"""
def __init__(self, coordinator, spa):
"""Initialize the entity."""
super().__init__(
coordinator,
spa,
"Error",
)
@property
def error(self) -> SpaError:
"""Return the underlying SpaError object for this entity."""
errors = self.coordinator.data[self.spa.id][ATTR_ERRORS]
if len(errors) == 0:
return None
return errors[0]
@property
def is_on(self) -> bool:
"""Return true if an error is signaled."""
return self.error is not None
@property
def extra_state_attributes(self):
"""Return the state attributes."""
error = self.error
if error is None:
return {}
return {
ATTR_ERROR_CODE: error.code,
ATTR_ERROR_TITLE: error.title,
ATTR_ERROR_DESCRIPTION: error.description,
ATTR_ERROR_TYPE: error.error_type,
ATTR_CREATED_AT: error.created_at.isoformat(),
ATTR_UPDATED_AT: error.updated_at.isoformat(),
}
@property
def device_class(self) -> str:
"""Return the device class for this entity."""
return DEVICE_CLASS_PROBLEM

View File

@ -21,6 +21,7 @@ DEFAULT_LIGHT_EFFECT = "purple"
# default to 50% brightness
DEFAULT_LIGHT_BRIGHTNESS = 128
ATTR_ERRORS = "errors"
ATTR_LIGHTS = "lights"
ATTR_PUMPS = "pumps"
ATTR_REMINDERS = "reminders"

View File

@ -16,6 +16,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import (
ATTR_ERRORS,
ATTR_LIGHTS,
ATTR_PUMPS,
ATTR_REMINDERS,
@ -92,15 +93,17 @@ class SmartTubController:
return data
async def _get_spa_data(self, spa):
full_status, reminders = await asyncio.gather(
full_status, reminders, errors = await asyncio.gather(
spa.get_status_full(),
spa.get_reminders(),
spa.get_errors(),
)
return {
ATTR_STATUS: full_status,
ATTR_PUMPS: {pump.id: pump for pump in full_status.pumps},
ATTR_LIGHTS: {light.zone: light for light in full_status.lights},
ATTR_REMINDERS: {reminder.id: reminder for reminder in reminders},
ATTR_ERRORS: errors,
}
async def async_register_devices(self, entry):

View File

@ -87,6 +87,8 @@ def mock_spa(spa_state):
mock_spa.get_reminders.return_value = [mock_filter_reminder]
mock_spa.get_errors.return_value = []
return mock_spa

View File

@ -1,5 +1,11 @@
"""Test the SmartTub binary sensor platform."""
from homeassistant.components.binary_sensor import STATE_OFF
from datetime import datetime
from unittest.mock import create_autospec
import pytest
import smarttub
from homeassistant.components.binary_sensor import STATE_OFF, STATE_ON
async def test_binary_sensors(spa, setup_entry, hass):
@ -10,6 +16,11 @@ async def test_binary_sensors(spa, setup_entry, hass):
# disabled by default
assert state is None
entity_id = f"binary_sensor.{spa.brand}_{spa.model}_error"
state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_OFF
async def test_reminders(spa, setup_entry, hass):
"""Test the reminder sensor."""
@ -21,6 +32,37 @@ async def test_reminders(spa, setup_entry, hass):
assert state.attributes["snoozed"] is False
@pytest.fixture
def mock_error(spa):
"""Mock error."""
error = create_autospec(smarttub.SpaError, instance=True)
error.code = 11
error.title = "Flow Switch Stuck Open"
error.description = None
error.active = True
error.created_at = datetime.now()
error.updated_at = datetime.now()
error.error_type = "TUB_ERROR"
return error
async def test_error(spa, hass, config_entry, mock_error):
"""Test the error sensor."""
spa.get_errors.return_value = [mock_error]
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entity_id = f"binary_sensor.{spa.brand}_{spa.model}_error"
state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_ON
assert state.attributes["error_code"] == 11
async def test_snooze(spa, setup_entry, hass):
"""Test snoozing a reminder."""