Improve amcrest error handling and bump amcrest package to 1.5.3 (#24262)
* Improve amcrest error handling and bump amcrest package to 1.5.3 amcrest package update fixes command retry, especially with Digest Authentication, and allows sending snapshot command without channel parameter. Get rid of persistent_notification. Errors at startup, other than login errors, are no longer fatal. Display debug messages about how many times an error has occurred in a row. Remove initial communications test. If camera is off line at startup this just delays the component setup. Handle urllib3 errors when getting data from commands that were sent with stream=True. If errors occur during camera update, try repeating until it works or the camera is determined to be off line. Drop channel parameter in snapshot command which allows camera to use its default channel, which is different in different camera models and firmware versions. Make entities unavailable if too many errors occur in a row. Add new configuration variables to control how many errors in a row should be interpreted as camera being offline, and how frequently to "ping" camera to see when it becomes available again. Add online binary_sensor option to indicate if camera is available (i.e., responding to commands.) * Update per review comments Remove max_errors and recheck_interval configuration variables and used fixed values instead. Move definition of AmcrestChecker class to module level. Change should_poll in camera.py to return a fixed value of True and move logic to update method.
This commit is contained in:
parent
61dabae6ab
commit
233bc1a108
9 changed files with 363 additions and 153 deletions
|
@ -5,17 +5,24 @@ import logging
|
|||
from amcrest import AmcrestError
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorDevice, DEVICE_CLASS_MOTION)
|
||||
BinarySensorDevice, DEVICE_CLASS_CONNECTIVITY, DEVICE_CLASS_MOTION)
|
||||
from homeassistant.const import CONF_NAME, CONF_BINARY_SENSORS
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
from .const import BINARY_SENSOR_SCAN_INTERVAL_SECS, DATA_AMCREST
|
||||
from .const import (
|
||||
BINARY_SENSOR_SCAN_INTERVAL_SECS, DATA_AMCREST, DEVICES, SERVICE_UPDATE)
|
||||
from .helpers import log_update_error, service_signal
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=BINARY_SENSOR_SCAN_INTERVAL_SECS)
|
||||
|
||||
BINARY_SENSOR_MOTION_DETECTED = 'motion_detected'
|
||||
BINARY_SENSOR_ONLINE = 'online'
|
||||
# Binary sensor types are defined like: Name, device class
|
||||
BINARY_SENSORS = {
|
||||
'motion_detected': 'Motion Detected'
|
||||
BINARY_SENSOR_MOTION_DETECTED: ('Motion Detected', DEVICE_CLASS_MOTION),
|
||||
BINARY_SENSOR_ONLINE: ('Online', DEVICE_CLASS_CONNECTIVITY),
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,7 +33,7 @@ async def async_setup_platform(hass, config, async_add_entities,
|
|||
return
|
||||
|
||||
name = discovery_info[CONF_NAME]
|
||||
device = hass.data[DATA_AMCREST]['devices'][name]
|
||||
device = hass.data[DATA_AMCREST][DEVICES][name]
|
||||
async_add_entities(
|
||||
[AmcrestBinarySensor(name, device, sensor_type)
|
||||
for sensor_type in discovery_info[CONF_BINARY_SENSORS]],
|
||||
|
@ -38,10 +45,18 @@ class AmcrestBinarySensor(BinarySensorDevice):
|
|||
|
||||
def __init__(self, name, device, sensor_type):
|
||||
"""Initialize entity."""
|
||||
self._name = '{} {}'.format(name, BINARY_SENSORS[sensor_type])
|
||||
self._name = '{} {}'.format(name, BINARY_SENSORS[sensor_type][0])
|
||||
self._signal_name = name
|
||||
self._api = device.api
|
||||
self._sensor_type = sensor_type
|
||||
self._state = None
|
||||
self._device_class = BINARY_SENSORS[sensor_type][1]
|
||||
self._unsub_dispatcher = None
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return True if entity has to be polled for state."""
|
||||
return self._sensor_type != BINARY_SENSOR_ONLINE
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -56,15 +71,39 @@ class AmcrestBinarySensor(BinarySensorDevice):
|
|||
@property
|
||||
def device_class(self):
|
||||
"""Return device class."""
|
||||
return DEVICE_CLASS_MOTION
|
||||
return self._device_class
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
"""Return True if entity is available."""
|
||||
return self._sensor_type == BINARY_SENSOR_ONLINE or self._api.available
|
||||
|
||||
def update(self):
|
||||
"""Update entity."""
|
||||
_LOGGER.debug('Pulling data from %s binary sensor', self._name)
|
||||
if not self.available:
|
||||
return
|
||||
_LOGGER.debug('Updating %s binary sensor', self._name)
|
||||
|
||||
try:
|
||||
self._state = self._api.is_motion_detected
|
||||
if self._sensor_type == BINARY_SENSOR_MOTION_DETECTED:
|
||||
self._state = self._api.is_motion_detected
|
||||
|
||||
elif self._sensor_type == BINARY_SENSOR_ONLINE:
|
||||
self._state = self._api.available
|
||||
except AmcrestError as error:
|
||||
_LOGGER.error(
|
||||
'Could not update %s binary sensor due to error: %s',
|
||||
self.name, error)
|
||||
log_update_error(
|
||||
_LOGGER, 'update', self.name, 'binary sensor', error)
|
||||
|
||||
async def async_on_demand_update(self):
|
||||
"""Update state."""
|
||||
self.async_schedule_update_ha_state(True)
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Subscribe to update signal."""
|
||||
self._unsub_dispatcher = async_dispatcher_connect(
|
||||
self.hass, service_signal(SERVICE_UPDATE, self._signal_name),
|
||||
self.async_on_demand_update)
|
||||
|
||||
async def async_will_remove_from_hass(self):
|
||||
"""Disconnect from update signal."""
|
||||
self._unsub_dispatcher()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue