Add save clips to Blink services (#84149)

This commit is contained in:
Brent Perdue 2023-06-01 14:06:53 -04:00 committed by GitHub
parent a1a055f618
commit 23ca26ae56
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 90 additions and 9 deletions

View file

@ -8,7 +8,13 @@ import voluptuous as vol
from homeassistant.components import persistent_notification
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry
from homeassistant.const import CONF_FILENAME, CONF_NAME, CONF_PIN, CONF_SCAN_INTERVAL
from homeassistant.const import (
CONF_FILE_PATH,
CONF_FILENAME,
CONF_NAME,
CONF_PIN,
CONF_SCAN_INTERVAL,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv
@ -18,6 +24,7 @@ from .const import (
DOMAIN,
PLATFORMS,
SERVICE_REFRESH,
SERVICE_SAVE_RECENT_CLIPS,
SERVICE_SAVE_VIDEO,
SERVICE_SEND_PIN,
)
@ -28,6 +35,9 @@ SERVICE_SAVE_VIDEO_SCHEMA = vol.Schema(
{vol.Required(CONF_NAME): cv.string, vol.Required(CONF_FILENAME): cv.string}
)
SERVICE_SEND_PIN_SCHEMA = vol.Schema({vol.Optional(CONF_PIN): cv.string})
SERVICE_SAVE_RECENT_CLIPS_SCHEMA = vol.Schema(
{vol.Required(CONF_NAME): cv.string, vol.Required(CONF_FILE_PATH): cv.string}
)
def _blink_startup_wrapper(hass: HomeAssistant, entry: ConfigEntry) -> Blink:
@ -100,6 +110,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Call save video service handler."""
await async_handle_save_video_service(hass, entry, call)
async def async_save_recent_clips(call):
"""Call save recent clips service handler."""
await async_handle_save_recent_clips_service(hass, entry, call)
def send_pin(call):
"""Call blink to send new pin."""
pin = call.data[CONF_PIN]
@ -112,6 +126,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.services.async_register(
DOMAIN, SERVICE_SAVE_VIDEO, async_save_video, schema=SERVICE_SAVE_VIDEO_SCHEMA
)
hass.services.async_register(
DOMAIN,
SERVICE_SAVE_RECENT_CLIPS,
async_save_recent_clips,
schema=SERVICE_SAVE_RECENT_CLIPS_SCHEMA,
)
hass.services.async_register(
DOMAIN, SERVICE_SEND_PIN, send_pin, schema=SERVICE_SEND_PIN_SCHEMA
)
@ -164,13 +184,33 @@ async def async_handle_save_video_service(hass, entry, call):
_LOGGER.error("Can't write %s, no access to path!", video_path)
return
def _write_video(camera_name, video_path):
def _write_video(name, file_path):
"""Call video write."""
all_cameras = hass.data[DOMAIN][entry.entry_id].cameras
if camera_name in all_cameras:
all_cameras[camera_name].video_to_file(video_path)
if name in all_cameras:
all_cameras[name].video_to_file(file_path)
try:
await hass.async_add_executor_job(_write_video, camera_name, video_path)
except OSError as err:
_LOGGER.error("Can't write image to file: %s", err)
async def async_handle_save_recent_clips_service(hass, entry, call):
"""Save multiple recent clips to output directory."""
camera_name = call.data[CONF_NAME]
clips_dir = call.data[CONF_FILE_PATH]
if not hass.config.is_allowed_path(clips_dir):
_LOGGER.error("Can't write to directory %s, no access to path!", clips_dir)
return
def _save_recent_clips(name, output_dir):
"""Call save recent clips."""
all_cameras = hass.data[DOMAIN][entry.entry_id].cameras
if name in all_cameras:
all_cameras[name].save_recent_clips(output_dir=output_dir)
try:
await hass.async_add_executor_job(_save_recent_clips, camera_name, clips_dir)
except OSError as err:
_LOGGER.error("Can't write recent clips to directory: %s", err)

View file

@ -55,8 +55,15 @@ class BlinkSyncModule(AlarmControlPanelEntity):
def update(self) -> None:
"""Update the state of the device."""
_LOGGER.debug("Updating Blink Alarm Control Panel %s", self._name)
self.data.refresh()
if self.data.check_if_ok_to_update():
_LOGGER.debug(
"Initiating a blink.refresh() from BlinkSyncModule('%s') (%s)",
self._name,
self.data,
)
self.data.refresh()
_LOGGER.info("Updating State of Blink Alarm Control Panel '%s'", self._name)
self._attr_state = (
STATE_ALARM_ARMED_AWAY if self.sync.arm else STATE_ALARM_DISARMED
)

View file

@ -1,6 +1,8 @@
"""Support for Blink system camera control."""
from __future__ import annotations
import logging
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
@ -20,6 +22,8 @@ from .const import (
TYPE_MOTION_DETECTED,
)
_LOGGER = logging.getLogger(__name__)
BINARY_SENSORS_TYPES: tuple[BinarySensorEntityDescription, ...] = (
BinarySensorEntityDescription(
key=TYPE_BATTERY,
@ -74,8 +78,13 @@ class BlinkBinarySensor(BinarySensorEntity):
def update(self) -> None:
"""Update sensor state."""
self.data.refresh()
state = self._camera.attributes[self.entity_description.key]
_LOGGER.debug(
"'%s' %s = %s",
self._camera.attributes["name"],
self.entity_description.key,
state,
)
if self.entity_description.key == TYPE_BATTERY:
state = state != "ok"
self._attr_is_on = state

View file

@ -23,6 +23,7 @@ TYPE_WIFI_STRENGTH = "wifi_strength"
SERVICE_REFRESH = "blink_update"
SERVICE_TRIGGER = "trigger_camera"
SERVICE_SAVE_VIDEO = "save_video"
SERVICE_SAVE_RECENT_CLIPS = "save_recent_clips"
SERVICE_SEND_PIN = "send_pin"
PLATFORMS = [

View file

@ -78,9 +78,14 @@ class BlinkSensor(SensorEntity):
def update(self) -> None:
"""Retrieve sensor data from the camera."""
self.data.refresh()
try:
self._attr_native_value = self._camera.attributes[self._sensor_key]
_LOGGER.debug(
"'%s' %s = %s",
self._camera.attributes["name"],
self._sensor_key,
self._attr_native_value,
)
except KeyError:
self._attr_native_value = None
_LOGGER.error(

View file

@ -25,12 +25,31 @@ save_video:
text:
filename:
name: File name
description: Filename to writable path (directory may need to be included in whitelist_dirs in config)
description: Filename to writable path (directory may need to be included in allowlist_external_dirs in config)
required: true
example: "/tmp/video.mp4"
selector:
text:
save_recent_clips:
name: Save recent clips
description: 'Save all recent video clips to local directory with file pattern "%Y%m%d_%H%M%S_{name}.mp4"'
fields:
name:
name: Name
description: Name of camera to grab recent clips from.
required: true
example: "Living Room"
selector:
text:
file_path:
name: Output directory
description: Directory name of writable path (directory may need to be included in allowlist_external_dirs in config)
required: true
example: "/tmp"
selector:
text:
send_pin:
name: Send pin
description: Send a new PIN to blink for 2FA.